From 3b8d91eb8eff050fb60daac751e9645d140b3421 Mon Sep 17 00:00:00 2001 From: jamshale <31809382+jamshale@users.noreply.github.com> Date: Wed, 12 Feb 2025 15:09:15 -0800 Subject: [PATCH 01/76] Allow schema id to be used during anoncreds issuance (#3497) * Allow schema id to be used during anoncreds issuance Signed-off-by: jamshale * Fix scenario test Signed-off-by: jamshale * Fix mistake in handler / Add unit tests Signed-off-by: jamshale * Try a sleep in between upgrades. Issue with github actions Signed-off-by: jamshale * Refactor based on PR review comments Signed-off-by: jamshale * Repair _fetch_schema_attr_names function call Signed-off-by: jamshale * Remove unnessecary self usage Signed-off-by: jamshale --------- Signed-off-by: jamshale --- .../v2_0/formats/anoncreds/handler.py | 61 ++++- .../formats/anoncreds/tests/test_handler.py | 221 ++++++++++++------ .../example.py | 110 ++++++++- .../restart_anoncreds_upgrade/example.py | 12 +- scenarios/examples/util.py | 2 +- 5 files changed, 314 insertions(+), 92 deletions(-) diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/handler.py b/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/handler.py index a25e4bb62c..0836a7b4e2 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/handler.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/handler.py @@ -2,14 +2,14 @@ import json import logging -from typing import Mapping, Optional, Tuple +from typing import List, Mapping, Optional, Tuple -from anoncreds import CredentialDefinition, Schema +from anoncreds import CredentialDefinition from marshmallow import RAISE -from ......anoncreds.base import AnonCredsResolutionError +from ......anoncreds.base import AnonCredsObjectNotFound, AnonCredsResolutionError from ......anoncreds.holder import AnonCredsHolder, AnonCredsHolderError -from ......anoncreds.issuer import CATEGORY_CRED_DEF, CATEGORY_SCHEMA, AnonCredsIssuer +from ......anoncreds.issuer import CATEGORY_CRED_DEF, AnonCredsIssuer from ......anoncreds.models.credential import AnoncredsCredentialSchema from ......anoncreds.models.credential_offer import AnoncredsCredentialOfferSchema from ......anoncreds.models.credential_proposal import ( @@ -204,15 +204,54 @@ async def _create(): offer_json = await issuer.create_credential_offer(cred_def_id) return json.loads(offer_json) - async with self.profile.session() as session: - cred_def_entry = await session.handle.fetch(CATEGORY_CRED_DEF, cred_def_id) - cred_def_dict = CredentialDefinition.load(cred_def_entry.value).to_dict() - schema_entry = await session.handle.fetch( - CATEGORY_SCHEMA, cred_def_dict["schemaId"] + async def _get_attr_names(schema_id) -> List[str] | None: + """Fetch attribute names for a given schema ID from the registry.""" + if not schema_id: + return None + try: + schema_result = await registry.get_schema(self.profile, schema_id) + return schema_result.schema.attr_names + except AnonCredsObjectNotFound: + LOGGER.info(f"Schema not found for schema_id={schema_id}") + return None + except AnonCredsResolutionError as e: + LOGGER.warning(f"Schema resolution failed for schema_id={schema_id}: {e}") + return None + + async def _fetch_schema_attr_names( + anoncreds_attachment, cred_def_id + ) -> List[str] | None: + """Determine schema attribute names from schema_id or cred_def_id.""" + schema_id = anoncreds_attachment.get("schema_id") + attr_names = await _get_attr_names(schema_id) + + if attr_names: + return attr_names + + if cred_def_id: + async with self.profile.session() as session: + cred_def_entry = await session.handle.fetch( + CATEGORY_CRED_DEF, cred_def_id + ) + cred_def_dict = CredentialDefinition.load( + cred_def_entry.value + ).to_dict() + return await _get_attr_names(cred_def_dict.get("schemaId")) + + return None + + attr_names = None + registry = self.profile.inject(AnonCredsRegistry) + + attr_names = await _fetch_schema_attr_names(anoncreds_attachment, cred_def_id) + + if not attr_names: + raise V20CredFormatError( + "Could not determine schema attributes. If you did not create the " + "schema, then you need to provide the schema_id." ) - schema_dict = Schema.load(schema_entry.value).to_dict() - schema_attrs = set(schema_dict["attrNames"]) + schema_attrs = set(attr_names) preview_attrs = set(cred_proposal_message.credential_preview.attr_dict()) if preview_attrs != schema_attrs: raise V20CredFormatError( diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/tests/test_handler.py b/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/tests/test_handler.py index 07f2d948c4..48bb244191 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/tests/test_handler.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/tests/test_handler.py @@ -4,13 +4,22 @@ from unittest import IsolatedAsyncioTestCase import pytest +from anoncreds import CredentialDefinition from marshmallow import ValidationError from .......anoncreds.holder import AnonCredsHolder from .......anoncreds.issuer import AnonCredsIssuer +from .......anoncreds.models.credential_definition import ( + CredDef, + CredDefValue, + CredDefValuePrimary, +) +from .......anoncreds.registry import AnonCredsRegistry from .......anoncreds.revocation import AnonCredsRevocationRegistryFullError from .......cache.base import BaseCache from .......cache.in_memory import InMemoryCache +from .......config.provider import ClassProvider +from .......indy.credx.issuer import CATEGORY_CRED_DEF from .......ledger.base import BaseLedger from .......ledger.multiple_ledger.ledger_requests_executor import ( IndyLedgerRequestsExecutor, @@ -193,9 +202,38 @@ class TestV20AnonCredsCredFormatHandler(IsolatedAsyncioTestCase): async def asyncSetUp(self): - self.profile = await create_test_profile() + self.profile = await create_test_profile( + { + "wallet.type": "askar-anoncreds", + } + ) self.context = self.profile.context + # Context + self.cache = InMemoryCache() + self.profile.context.injector.bind_instance(BaseCache, self.cache) + + # Issuer + self.issuer = mock.MagicMock(AnonCredsIssuer, autospec=True) + self.profile.context.injector.bind_instance(AnonCredsIssuer, self.issuer) + + # Holder + self.holder = mock.MagicMock(AnonCredsHolder, autospec=True) + self.profile.context.injector.bind_instance(AnonCredsHolder, self.holder) + + # Anoncreds registry + self.profile.context.injector.bind_instance( + AnonCredsRegistry, AnonCredsRegistry() + ) + registry = self.profile.context.inject_or(AnonCredsRegistry) + legacy_indy_registry = ClassProvider( + "acapy_agent.anoncreds.default.legacy_indy.registry.LegacyIndyRegistry", + # supported_identifiers=[], + # method_name="", + ).provide(self.profile.context.settings, self.profile.context.injector) + await legacy_indy_registry.setup(self.profile.context) + registry.register(legacy_indy_registry) + # Ledger self.ledger = mock.MagicMock(BaseLedger, autospec=True) self.ledger.get_schema = mock.CoroutineMock(return_value=SCHEMA) @@ -214,18 +252,6 @@ async def asyncSetUp(self): ) ), ) - # Context - self.cache = InMemoryCache() - self.profile.context.injector.bind_instance(BaseCache, self.cache) - - # Issuer - self.issuer = mock.MagicMock(AnonCredsIssuer, autospec=True) - self.profile.context.injector.bind_instance(AnonCredsIssuer, self.issuer) - - # Holder - self.holder = mock.MagicMock(AnonCredsHolder, autospec=True) - self.profile.context.injector.bind_instance(AnonCredsHolder, self.holder) - self.handler = AnonCredsCredFormatHandler(self.profile) assert self.handler.profile @@ -338,68 +364,123 @@ async def test_receive_proposal(self): # Not much to assert. Receive proposal doesn't do anything await self.handler.receive_proposal(cred_ex_record, cred_proposal_message) - @pytest.mark.skip(reason="Anoncreds-break") - async def test_create_offer(self): - schema_id_parts = SCHEMA_ID.split(":") - - cred_preview = V20CredPreview( - attributes=( - V20CredAttrSpec(name="legalName", value="value"), - V20CredAttrSpec(name="jurisdictionId", value="value"), - V20CredAttrSpec(name="incorporationDate", value="value"), - ) - ) - - cred_proposal = V20CredProposal( - credential_preview=cred_preview, - formats=[ - V20CredFormat( - attach_id="0", - format_=ATTACHMENT_FORMAT[CRED_20_PROPOSAL][ - V20CredFormat.Format.ANONCREDS.api + async def test_create_offer_cant_find_schema_in_wallet_or_data_registry(self): + with self.assertRaises(V20CredFormatError): + await self.handler.create_offer( + V20CredProposal( + formats=[ + V20CredFormat( + attach_id="0", + format_=ATTACHMENT_FORMAT[CRED_20_PROPOSAL][ + V20CredFormat.Format.ANONCREDS.api + ], + ) + ], + filters_attach=[ + AttachDecorator.data_base64( + {"cred_def_id": CRED_DEF_ID}, ident="0" + ) ], ) - ], - filters_attach=[ - AttachDecorator.data_base64({"cred_def_id": CRED_DEF_ID}, ident="0") - ], - ) + ) - cred_def_record = StorageRecord( - CRED_DEF_SENT_RECORD_TYPE, - CRED_DEF_ID, - { - "schema_id": SCHEMA_ID, - "schema_issuer_did": schema_id_parts[0], - "schema_name": schema_id_parts[-2], - "schema_version": schema_id_parts[-1], - "issuer_did": TEST_DID, - "cred_def_id": CRED_DEF_ID, - "epoch": str(int(time())), - }, + @mock.patch.object( + AnonCredsRegistry, + "get_schema", + mock.CoroutineMock( + return_value=mock.MagicMock(schema=mock.MagicMock(attr_names=["score"])) + ), + ) + @mock.patch.object( + AnonCredsIssuer, + "create_credential_offer", + mock.CoroutineMock(return_value=json.dumps(ANONCREDS_OFFER)), + ) + @mock.patch.object( + CredentialDefinition, + "load", + mock.MagicMock(to_dict=mock.MagicMock(return_value={"schemaId": SCHEMA_ID})), + ) + async def test_create_offer(self): + self.issuer.create_credential_offer = mock.CoroutineMock({}) + # With a schema_id + await self.handler.create_offer( + V20CredProposal( + credential_preview=V20CredPreview( + attributes=(V20CredAttrSpec(name="score", value="0"),) + ), + formats=[ + V20CredFormat( + attach_id="0", + format_=ATTACHMENT_FORMAT[CRED_20_PROPOSAL][ + V20CredFormat.Format.ANONCREDS.api + ], + ) + ], + filters_attach=[ + AttachDecorator.data_base64( + {"cred_def_id": CRED_DEF_ID, "schema_id": SCHEMA_ID}, ident="0" + ) + ], + ) ) - await self.session.storage.add_record(cred_def_record) - - self.issuer.create_credential_offer = mock.CoroutineMock( - return_value=json.dumps(ANONCREDS_OFFER) + # Only with cred_def_id + async with self.profile.session() as session: + await session.handle.insert( + CATEGORY_CRED_DEF, + CRED_DEF_ID, + CredDef( + issuer_id=TEST_DID, + schema_id=SCHEMA_ID, + tag="tag", + type="CL", + value=CredDefValue( + primary=CredDefValuePrimary("n", "s", {}, "rctxt", "z") + ), + ).to_json(), + tags={}, + ) + await self.handler.create_offer( + V20CredProposal( + credential_preview=V20CredPreview( + attributes=(V20CredAttrSpec(name="score", value="0"),) + ), + formats=[ + V20CredFormat( + attach_id="0", + format_=ATTACHMENT_FORMAT[CRED_20_PROPOSAL][ + V20CredFormat.Format.ANONCREDS.api + ], + ) + ], + filters_attach=[ + AttachDecorator.data_base64({"cred_def_id": CRED_DEF_ID}, ident="0") + ], + ) ) - - (cred_format, attachment) = await self.handler.create_offer(cred_proposal) - - self.issuer.create_credential_offer.assert_called_once_with(CRED_DEF_ID) - - # assert identifier match - assert cred_format.attach_id == self.handler.format.api == attachment.ident - - # assert content of attachment is proposal data - assert attachment.content == ANONCREDS_OFFER - - # assert data is encoded as base64 - assert attachment.data.base64 - - self.issuer.create_credential_offer.reset_mock() - await self.handler.create_offer(cred_proposal) - self.issuer.create_credential_offer.assert_not_called() + # Wrong attribute name + with self.assertRaises(V20CredFormatError): + await self.handler.create_offer( + V20CredProposal( + credential_preview=V20CredPreview( + attributes=(V20CredAttrSpec(name="wrong", value="0"),) + ), + formats=[ + V20CredFormat( + attach_id="0", + format_=ATTACHMENT_FORMAT[CRED_20_PROPOSAL][ + V20CredFormat.Format.ANONCREDS.api + ], + ) + ], + filters_attach=[ + AttachDecorator.data_base64( + {"cred_def_id": CRED_DEF_ID, "schema_id": SCHEMA_ID}, + ident="0", + ) + ], + ) + ) @pytest.mark.skip(reason="Anoncreds-break") async def test_create_offer_no_cache(self): diff --git a/scenarios/examples/anoncreds_issuance_and_revocation/example.py b/scenarios/examples/anoncreds_issuance_and_revocation/example.py index d74a813b40..b38beb64d9 100644 --- a/scenarios/examples/anoncreds_issuance_and_revocation/example.py +++ b/scenarios/examples/anoncreds_issuance_and_revocation/example.py @@ -36,6 +36,7 @@ async def main(): """Test Controller protocols.""" issuer_name = "issuer" + token_hex(8) + issuer_without_schema_name = "issuer" + token_hex(8) async with Controller(base_url=AGENCY) as agency: issuer = await agency.post( "/multitenancy/wallet", @@ -46,6 +47,15 @@ async def main(): }, response=CreateWalletResponse, ) + issuer_without_schema = await agency.post( + "/multitenancy/wallet", + json={ + "label": issuer_without_schema_name, + "wallet_name": issuer_without_schema_name, + "wallet_type": "askar", + }, + response=CreateWalletResponse, + ) async with ( Controller( @@ -53,6 +63,11 @@ async def main(): wallet_id=issuer.wallet_id, subwallet_token=issuer.token, ) as issuer, + Controller( + base_url=AGENCY, + wallet_id=issuer_without_schema.wallet_id, + subwallet_token=issuer_without_schema.token, + ) as issuer_without_schema, Controller(base_url=HOLDER_ANONCREDS) as holder_anoncreds, Controller(base_url=HOLDER_INDY) as holder_indy, ): @@ -113,8 +128,8 @@ async def main(): holder_anoncreds, issuer_conn_with_anoncreds_holder.connection_id, holder_anoncreds_conn.connection_id, - cred_def.credential_definition_id, {"firstname": "Anoncreds", "lastname": "Holder"}, + cred_def_id=cred_def.credential_definition_id, issuer_id=public_did.did, schema_id=schema.schema_id, schema_issuer_id=public_did.did, @@ -162,8 +177,8 @@ async def main(): holder_indy, issuer_conn_with_indy_holder.connection_id, holder_indy_conn.connection_id, - cred_def.credential_definition_id, {"firstname": "Indy", "lastname": "Holder"}, + cred_def_id=cred_def.credential_definition_id, issuer_id=public_did.did, schema_id=schema.schema_id, schema_issuer_id=public_did.did, @@ -214,7 +229,15 @@ async def main(): "wallet_name": issuer_name, }, ) + # Wait for the upgrade to complete + await asyncio.sleep(1) + await issuer_without_schema.post( + "/anoncreds/wallet/upgrade", + params={ + "wallet_name": issuer_without_schema_name, + }, + ) # Wait for the upgrade to complete await asyncio.sleep(2) @@ -275,8 +298,8 @@ async def main(): holder_anoncreds, issuer_conn_with_anoncreds_holder.connection_id, holder_anoncreds_conn.connection_id, - cred_def.credential_definition_state["credential_definition_id"], {"middlename": "Anoncreds"}, + cred_def_id=cred_def.credential_definition_state["credential_definition_id"], issuer_id=public_did.did, schema_id=schema.schema_state["schema_id"], schema_issuer_id=public_did.did, @@ -310,8 +333,8 @@ async def main(): holder_indy, issuer_conn_with_indy_holder.connection_id, holder_indy_conn.connection_id, - cred_def.credential_definition_state["credential_definition_id"], {"middlename": "Indy"}, + cred_def_id=cred_def.credential_definition_state["credential_definition_id"], issuer_id=public_did.did, schema_id=schema.schema_state["schema_id"], schema_issuer_id=public_did.did, @@ -340,6 +363,85 @@ async def main(): await holder_indy.record(topic="revocation-notification") + """ + This section of the test script demonstrates the issuance, presentation and + revocation of a credential where the issuer did not create the schema. + """ + print( + "***Begin issuance, presentation and revocation of " + "credential without schema***" + ) + issuer_conn_with_anoncreds_holder, holder_anoncreds_conn = await didexchange( + issuer_without_schema, holder_anoncreds + ) + + public_did = ( + await issuer_without_schema.post( + "/wallet/did/create", + json={"method": "sov", "options": {"key_type": "ed25519"}}, + response=DIDResult, + ) + ).result + assert public_did + + async with ClientSession() as session: + register_url = genesis_url.replace("/genesis", "/register") + async with session.post( + register_url, + json={ + "did": public_did.did, + "verkey": public_did.verkey, + "alias": None, + "role": "ENDORSER", + }, + ) as resp: + assert resp.ok + + await issuer_without_schema.post( + "/wallet/did/public", params=params(did=public_did.did) + ) + cred_def = await issuer_without_schema.post( + "/anoncreds/credential-definition", + json={ + "credential_definition": { + "issuerId": public_did.did, + "schemaId": schema.schema_state["schema_id"], + "tag": token_hex(8), + }, + "options": {"support_revocation": True, "revocation_registry_size": 10}, + }, + response=CredDefResultAnoncreds, + ) + issuer_cred_ex, _ = await anoncreds_issue_credential_v2( + issuer_without_schema, + holder_anoncreds, + issuer_conn_with_anoncreds_holder.connection_id, + holder_anoncreds_conn.connection_id, + {"middlename": "Anoncreds"}, + cred_def_id=cred_def.credential_definition_state["credential_definition_id"], + schema_id=schema.schema_state["schema_id"], + ) + await anoncreds_present_proof_v2( + holder_anoncreds, + issuer_without_schema, + holder_anoncreds_conn.connection_id, + issuer_conn_with_anoncreds_holder.connection_id, + requested_attributes=[{"name": "middlename"}], + ) + await issuer_without_schema.post( + url="/anoncreds/revocation/revoke", + json={ + "connection_id": issuer_conn_with_anoncreds_holder.connection_id, + "rev_reg_id": issuer_cred_ex.details.rev_reg_id, + "cred_rev_id": issuer_cred_ex.details.cred_rev_id, + "publish": True, + "notify": True, + "notify_version": "v1_0", + }, + ) + + await holder_anoncreds.record(topic="revocation-notification") + if __name__ == "__main__": logging_to_stdout() diff --git a/scenarios/examples/restart_anoncreds_upgrade/example.py b/scenarios/examples/restart_anoncreds_upgrade/example.py index b73b46e5d8..ee1305f969 100644 --- a/scenarios/examples/restart_anoncreds_upgrade/example.py +++ b/scenarios/examples/restart_anoncreds_upgrade/example.py @@ -56,8 +56,8 @@ async def connect_agents_and_issue_credentials( invitee, inviter_conn.connection_id, invitee_conn.connection_id, - inviter_cred_def.credential_definition_id, {"firstname": fname, "lastname": lname}, + inviter_cred_def.credential_definition_id, ) # Present the the credential's attributes @@ -105,8 +105,8 @@ async def connect_agents_and_issue_credentials( invitee, inviter_conn.connection_id, invitee_conn.connection_id, - inviter_cred_def.credential_definition_id, {"firstname": f"{fname}2", "lastname": f"{lname}2"}, + inviter_cred_def.credential_definition_id, ) print(">>> Done!") @@ -154,7 +154,7 @@ async def verify_issued_credentials(issuer, issued_cred_count, revoked_cred_coun rev_reg_id = cred_exch[cred_type]["rev_reg_id"] cred_rev_id = cred_exch[cred_type]["cred_rev_id"] cred_rev_id = int(cred_rev_id) - if not rev_reg_id in registries: + if rev_reg_id not in registries: if is_issuer_anoncreds: registries[rev_reg_id] = await issuer.get( f"/anoncreds/revocation/registry/{rev_reg_id}/issued/indy_recs", @@ -177,7 +177,7 @@ async def verify_recd_credentials(holder, active_cred_count, revoked_cred_count) "wallet.type" ) == "askar-anoncreds" - credentials = await holder.get(f"/credentials") + credentials = await holder.get("/credentials") credentials = credentials["results"] assert len(credentials) == (active_cred_count + revoked_cred_count) registries = {} @@ -186,7 +186,7 @@ async def verify_recd_credentials(holder, active_cred_count, revoked_cred_count) for credential in credentials: rev_reg_id = credential["rev_reg_id"] cred_rev_id = int(credential["cred_rev_id"]) - if not rev_reg_id in registries: + if rev_reg_id not in registries: if is_holder_anoncreds: registries[rev_reg_id] = await holder.get( f"/anoncreds/revocation/registry/{rev_reg_id}/issued/indy_recs", @@ -205,7 +205,7 @@ async def verify_recd_credentials(holder, active_cred_count, revoked_cred_count) async def verify_recd_presentations(verifier, recd_pres_count): - presentations = await verifier.get(f"/present-proof-2.0/records") + presentations = await verifier.get("/present-proof-2.0/records") presentations = presentations["results"] assert recd_pres_count == len(presentations) diff --git a/scenarios/examples/util.py b/scenarios/examples/util.py index b323b88b86..f7d54e15d0 100644 --- a/scenarios/examples/util.py +++ b/scenarios/examples/util.py @@ -200,8 +200,8 @@ async def anoncreds_issue_credential_v2( holder: Controller, issuer_connection_id: str, holder_connection_id: str, - cred_def_id: str, attributes: Mapping[str, str], + cred_def_id: str, issuer_id: Optional[str] = None, schema_id: Optional[str] = None, schema_issuer_id: Optional[str] = None, From ab8ec2dfd47aad2f3092199e822dc5b6d4b39016 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 13 Feb 2025 16:06:10 +0200 Subject: [PATCH 02/76] :construction_worker: Dependabot: don't ignore major releases Signed-off-by: ff137 --- .github/dependabot.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 67ce87084c..17836ba345 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -21,9 +21,6 @@ updates: day: "monday" time: "04:00" timezone: "Canada/Pacific" - ignore: - - dependency-name: "*" - update-types: ["version-update:semver-major"] # Maintain dependencies for Python Packages - package-ecosystem: "pip" @@ -33,9 +30,6 @@ updates: day: "monday" time: "04:00" timezone: "Canada/Pacific" - ignore: - - dependency-name: "*" - update-types: ["version-update:semver-major"] # Maintain dependencies for Python Packages - package-ecosystem: "pip" @@ -45,9 +39,6 @@ updates: day: "monday" time: "04:00" timezone: "Canada/Pacific" - ignore: - - dependency-name: "*" - update-types: ["version-update:semver-major"] # Maintain dependencies for Python Packages - package-ecosystem: "pip" @@ -57,9 +48,6 @@ updates: day: "monday" time: "04:00" timezone: "Canada/Pacific" - ignore: - - dependency-name: "*" - update-types: ["version-update:semver-major"] # Maintain dependencies for docker - package-ecosystem: "docker" From b12e023d086040c8705a2cc791dee55ea24ae8fc Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Thu, 13 Feb 2025 18:27:39 +0200 Subject: [PATCH 03/76] :heavy_plus_sign: Re-add `git` to Dockerfile (#3515) See https://github.com/openwallet-foundation/acapy/pull/3498/files#r1954246291 Signed-off-by: ff137 --- docker/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/Dockerfile b/docker/Dockerfile index 468d72cb28..1c4d5e6e37 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -47,6 +47,7 @@ RUN apt-get update -y && \ apt-transport-https \ ca-certificates \ curl \ + git \ libffi-dev \ libgmp10 \ libncurses5 \ From 69992cd51397ac49fea843c84a03c12e2e4af8fc Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Thu, 13 Feb 2025 18:45:32 +0200 Subject: [PATCH 04/76] :art: Include the validation error in Unprocessable Entity reason (#3517) Just raising the `HTTPUnprocessableEntity` exception doesn't report the validation error to the client Signed-off-by: ff137 Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- acapy_agent/admin/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acapy_agent/admin/server.py b/acapy_agent/admin/server.py index 111d2f2a52..c526e75435 100644 --- a/acapy_agent/admin/server.py +++ b/acapy_agent/admin/server.py @@ -176,7 +176,7 @@ async def ready_middleware(request: web.BaseRequest, handler: Coroutine): request.path, validation_error_message, ) - raise + raise web.HTTPUnprocessableEntity(reason=validation_error_message) from e except (LedgerConfigError, LedgerTransactionError) as e: # fatal, signal server shutdown LOGGER.critical("Shutdown with %s", str(e)) From 6db24387cd163c882544a0952c148a955c5b3cac Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 13 Feb 2025 18:48:54 +0200 Subject: [PATCH 05/76] :construction_worker: Ignore patch releases instead Signed-off-by: ff137 --- .github/dependabot.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 17836ba345..6fa45ac069 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -21,6 +21,9 @@ updates: day: "monday" time: "04:00" timezone: "Canada/Pacific" + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-patch"] # Maintain dependencies for Python Packages - package-ecosystem: "pip" @@ -30,6 +33,9 @@ updates: day: "monday" time: "04:00" timezone: "Canada/Pacific" + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-patch"] # Maintain dependencies for Python Packages - package-ecosystem: "pip" @@ -39,6 +45,9 @@ updates: day: "monday" time: "04:00" timezone: "Canada/Pacific" + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-patch"] # Maintain dependencies for Python Packages - package-ecosystem: "pip" @@ -48,6 +57,9 @@ updates: day: "monday" time: "04:00" timezone: "Canada/Pacific" + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-patch"] # Maintain dependencies for docker - package-ecosystem: "docker" From 7a795d107409818f9d6be35e241d0e3d4795e335 Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Thu, 13 Feb 2025 19:17:40 +0200 Subject: [PATCH 06/76] :zap: Remove `--cov` from pytest.ini_options (#3522) Signed-off-by: ff137 Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d5772778c4..1c0419555e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -130,7 +130,7 @@ line-length = 90 testpaths = "acapy_agent" addopts = """ --quiet --junitxml=./test-reports/junit.xml - --cov-config .coveragerc --cov=acapy_agent --cov-report term --cov-report xml + --cov-config .coveragerc --cov-report term --cov-report xml --ruff """ markers = [ @@ -139,7 +139,7 @@ markers = [ "indy: Tests specifically relating to Hyperledger Indy SDK support", "indy_credx: Tests specifically relating to Indy-Credx support", "indy_vdr: Tests specifically relating to Indy-VDR support", - "ursa_bbs_signatures: Tests specificaly relating to BBS Signatures support", + "ursa_bbs_signatures: Tests specifically relating to BBS Signatures support", "postgres: Tests relating to the postgres storage plugin for Indy", ] junit_family = "xunit1" From 008523326ba51877b08fdd7d116e7a43951e929f Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Fri, 14 Feb 2025 01:28:41 +0200 Subject: [PATCH 07/76] :white_check_mark: Fix demo playground example tests (#3531) * :arrow_up: Upgrade pytest to 8.3.4 Signed-off-by: ff137 * :art: Fix pyproject.toml for examples Signed-off-by: ff137 * :arrow_up: Update lock file Signed-off-by: ff137 * :art: Assign default urls Signed-off-by: ff137 * :white_check_mark: Fix fixture scope renamed from `loop_scope` Signed-off-by: ff137 * :art: Fix ruff errors Signed-off-by: ff137 --------- Signed-off-by: ff137 --- demo/playground/examples/poetry.lock | 262 +++++++++--------- demo/playground/examples/pyproject.toml | 6 +- demo/playground/examples/tests/__init__.py | 9 +- .../tests/test_mediator_ping_agents.py | 30 +- .../examples/tests/test_ping_agents.py | 22 +- 5 files changed, 166 insertions(+), 163 deletions(-) diff --git a/demo/playground/examples/poetry.lock b/demo/playground/examples/poetry.lock index 01ab4e8b52..96749e1948 100644 --- a/demo/playground/examples/poetry.lock +++ b/demo/playground/examples/poetry.lock @@ -1,124 +1,117 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. - -[[package]] -name = "asynctest" -version = "0.13.0" -description = "Enhance the standard unittest package with features for testing asyncio libraries" -optional = false -python-versions = ">=3.5" -files = [ - {file = "asynctest-0.13.0-py3-none-any.whl", hash = "sha256:5da6118a7e6d6b54d83a8f7197769d046922a44d2a99c21382f0a6e4fadae676"}, - {file = "asynctest-0.13.0.tar.gz", hash = "sha256:c27862842d15d83e6a34eb0b2866c323880eb3a75e4485b079ea11748fd77fac"}, -] +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. [[package]] name = "certifi" -version = "2024.7.4" +version = "2025.1.31" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ - {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, - {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, + {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, + {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, ] [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.7" +groups = ["main"] files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, + {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, + {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, ] [[package]] @@ -127,6 +120,8 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main"] +markers = "sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -134,21 +129,26 @@ files = [ [[package]] name = "idna" -version = "3.7" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" +groups = ["main"] files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -156,13 +156,14 @@ files = [ [[package]] name = "packaging" -version = "24.0" +version = "24.2" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -171,6 +172,7 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -182,23 +184,24 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pytest" -version = "7.4.4" +version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, - {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, + {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, + {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, ] [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<2.0" +pluggy = ">=1.5,<2" [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" @@ -206,6 +209,7 @@ version = "0.23.8" description = "Pytest support for asyncio" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pytest_asyncio-0.23.8-py3-none-any.whl", hash = "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2"}, {file = "pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3"}, @@ -224,6 +228,7 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -241,13 +246,14 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "urllib3" -version = "2.2.2" +version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" +groups = ["main"] files = [ - {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, - {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, + {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, + {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, ] [package.extras] @@ -257,6 +263,6 @@ socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [metadata] -lock-version = "2.0" -python-versions = "^3.9" -content-hash = "e7c40d4cc94149e4ea177a217c63b63f9b0c03ef26a86976200877bc78eb4606" +lock-version = "2.1" +python-versions = "^3.12" +content-hash = "3d25008515cd2a124d4b920fd61465d2ac24634e0646cbc5851100af2c3a49ad" diff --git a/demo/playground/examples/pyproject.toml b/demo/playground/examples/pyproject.toml index 3d4cccc282..a283133e33 100644 --- a/demo/playground/examples/pyproject.toml +++ b/demo/playground/examples/pyproject.toml @@ -3,16 +3,14 @@ name = "acapy_demos_playground" version = "0.1.0" description = "" authors = ["Jason Sherman "] +package-mode=false [tool.poetry.dependencies] python = "^3.12" -pytest = "^7.4.4" +pytest = "^8.3.4" pytest-asyncio = "^0.23.8" -asynctest = "^0.13.0" requests = "^2.32.3" -[tool.poetry.dev-dependencies] - [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" \ No newline at end of file diff --git a/demo/playground/examples/tests/__init__.py b/demo/playground/examples/tests/__init__.py index 25e55628ef..a67f9c0688 100644 --- a/demo/playground/examples/tests/__init__.py +++ b/demo/playground/examples/tests/__init__.py @@ -2,7 +2,6 @@ import logging import os -import time from functools import wraps import pytest @@ -10,10 +9,10 @@ AUTO_ACCEPT = "false" -FABER = os.getenv("FABER") -ALICE = os.getenv("ALICE") -ACME = os.getenv("ACME") -MULTI = os.getenv("MULTI") +FABER = os.getenv("FABER", "http://faber-agent:9011") +ALICE = os.getenv("ALICE", "http://alice-agent:9012") +ACME = os.getenv("ACME", "http://acme-agent:9013") +MULTI = os.getenv("MULTI", "http://multi-agent:9014") # Create a named logger logger = logging.getLogger("playground_examples") diff --git a/demo/playground/examples/tests/test_mediator_ping_agents.py b/demo/playground/examples/tests/test_mediator_ping_agents.py index 7b1a1c4af5..938785e93a 100644 --- a/demo/playground/examples/tests/test_mediator_ping_agents.py +++ b/demo/playground/examples/tests/test_mediator_ping_agents.py @@ -16,21 +16,21 @@ logger.info("start testing mediated connections...") -@pytest.fixture(loop_scope="session") +@pytest.fixture(scope="session") def faber(): """faber agent fixture.""" logger.info(f"faber = {FABER}") yield Agent(FABER) -@pytest.fixture(loop_scope="session") +@pytest.fixture(scope="session") def alice(): """resolver agent fixture.""" logger.info(f"alice = {ALICE}") yield Agent(ALICE) -@pytest.fixture(loop_scope="session") +@pytest.fixture(scope="session") def multi_one(): """resolver agent fixture.""" agent = Agent(MULTI) @@ -42,7 +42,7 @@ def multi_one(): yield agent -@pytest.fixture(loop_scope="session") +@pytest.fixture(scope="session") def mediation_invite(): invitation_url = os.getenv("MEDIATOR_INVITATION_URL") logger.info(f"MEDIATOR_INVITATION_URL = {invitation_url}") @@ -97,7 +97,7 @@ def initialize_mediation(agent: Agent, invitation): return result -@pytest.fixture(loop_scope="session") +@pytest.fixture(scope="session") def faber_mediator(faber, mediation_invite): logger.info("faber_mediator...") result = initialize_mediation(faber, mediation_invite) @@ -105,7 +105,7 @@ def faber_mediator(faber, mediation_invite): yield result -@pytest.fixture(loop_scope="session") +@pytest.fixture(scope="session") def alice_mediator(alice, mediation_invite): logger.info("alice_mediator...") result = initialize_mediation(alice, mediation_invite) @@ -113,7 +113,7 @@ def alice_mediator(alice, mediation_invite): yield result -@pytest.fixture(loop_scope="session") +@pytest.fixture(scope="session") def multi_one_mediator(multi_one, mediation_invite): logger.info("multi_one_mediator...") result = initialize_mediation(multi_one, mediation_invite) @@ -128,8 +128,8 @@ def multi_one_mediator(multi_one, mediation_invite): def test_mediated_single_tenants( faber, alice, faber_mediator, alice_mediator, mediation_invite ): - assert faber_mediator["mediation_granted"] == True - assert alice_mediator["mediation_granted"] == True + assert faber_mediator["mediation_granted"] is True + assert alice_mediator["mediation_granted"] is True resp = faber.create_invitation( alias="alice", @@ -171,8 +171,8 @@ def test_mediated_single_tenants( logger.info(f"alice/faber active? {alice_faber_connection_active}") attempts = attempts + 1 - assert faber_alice_connection_active == True - assert alice_faber_connection_active == True + assert faber_alice_connection_active is True + assert alice_faber_connection_active is True logger.info("faber alice pinging...") pings = 0 @@ -193,8 +193,8 @@ def test_mediated_single_tenants( def test_mediated_multi_tenants( multi_one, alice, multi_one_mediator, alice_mediator, mediation_invite ): - assert multi_one_mediator["mediation_granted"] == True - assert alice_mediator["mediation_granted"] == True + assert multi_one_mediator["mediation_granted"] is True + assert alice_mediator["mediation_granted"] is True resp = multi_one.create_invitation( alias="alice", @@ -239,8 +239,8 @@ def test_mediated_multi_tenants( logger.info(f"alice/multi_one active? {alice_multi_one_connection_active}") attempts = attempts + 1 - assert multi_one_alice_connection_active == True - assert alice_multi_one_connection_active == True + assert multi_one_alice_connection_active is True + assert alice_multi_one_connection_active is True logger.info("multi_one alice pinging...") pings = 0 diff --git a/demo/playground/examples/tests/test_ping_agents.py b/demo/playground/examples/tests/test_ping_agents.py index 13846181f8..3ea0a9d077 100644 --- a/demo/playground/examples/tests/test_ping_agents.py +++ b/demo/playground/examples/tests/test_ping_agents.py @@ -11,19 +11,19 @@ from . import ALICE, FABER, MULTI, Agent, logger -@pytest.fixture(loop_scope="session") +@pytest.fixture(scope="session") def faber(): """faber agent fixture.""" yield Agent(FABER) -@pytest.fixture(loop_scope="session") +@pytest.fixture(scope="session") def alice(): """resolver agent fixture.""" yield Agent(ALICE) -@pytest.fixture(loop_scope="session") +@pytest.fixture(scope="session") def multi_one(): """resolver agent fixture.""" agent = Agent(MULTI) @@ -35,7 +35,7 @@ def multi_one(): yield agent -@pytest.fixture(loop_scope="session", autouse=True) +@pytest.fixture(scope="session", autouse=True) def alice_faber_connection(faber, alice): """Established connection filter.""" logger.info("faber create invitation to alice") @@ -48,7 +48,7 @@ def alice_faber_connection(faber, alice): return result -@pytest.fixture(loop_scope="session", autouse=True) +@pytest.fixture(scope="session", autouse=True) def faber_alice_connection(faber, alice): """Established connection filter.""" logger.info("alice create invitation to faber") @@ -61,7 +61,7 @@ def faber_alice_connection(faber, alice): return result -@pytest.fixture(loop_scope="session", autouse=True) +@pytest.fixture(scope="session", autouse=True) def alice_multi_one_connection(multi_one, alice): """Established connection filter.""" logger.info("multi_one create invitation to alice") @@ -74,7 +74,7 @@ def alice_multi_one_connection(multi_one, alice): return result -@pytest.fixture(loop_scope="session", autouse=True) +@pytest.fixture(scope="session", autouse=True) def multi_one_alice_connection(multi_one, alice): """Established connection filter.""" logger.info("alice create invitation to multi_one") @@ -110,8 +110,8 @@ def test_single_tenants(faber, alice, faber_alice_connection, alice_faber_connec logger.info(f"alice/faber active? {alice_faber_connection_active}") attempts = attempts + 1 - assert faber_alice_connection_active == True - assert alice_faber_connection_active == True + assert faber_alice_connection_active is True + assert alice_faber_connection_active is True logger.info("faber alice pinging...") pings = 0 @@ -150,8 +150,8 @@ def test_multi_tenants( logger.info(f"alice/multi_one active? {alice_multi_one_connection_active}") attempts = attempts + 1 - assert multi_one_alice_connection_active == True - assert alice_multi_one_connection_active == True + assert multi_one_alice_connection_active is True + assert alice_multi_one_connection_active is True logger.info("multi_one alice pinging...") pings = 0 From 99971350cc00678b9606887b1495494f5beb2347 Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Fri, 14 Feb 2025 02:41:22 +0200 Subject: [PATCH 08/76] :arrow_up: Upgrade sphinx versions in docs (#3530) * :heavy_minus_sign: Remove sphinx dependencies from main app Signed-off-by: ff137 * :arrow_up: Upgrade build os to ubuntu-24 Signed-off-by: ff137 * :art: Remove unused, sample extension config Signed-off-by: ff137 * :arrow_up: Upgrade docs requirements Signed-off-by: ff137 * :recycle: Regenerated docs rst files Signed-off-by: ff137 * :memo: Add pip install instruction to readme Signed-off-by: ff137 --------- Signed-off-by: ff137 Co-authored-by: Stephen Curran --- .readthedocs.yaml | 2 +- docs/UpdateRTD.md | 6 +- docs/conf.py | 3 - docs/generated/acapy_agent.connections.rst | 8 + .../acapy_agent.protocols.connections.rst | 26 -- ...nt.protocols.connections.v1_0.handlers.rst | 42 --- ...nt.protocols.connections.v1_0.messages.rst | 42 --- ...gent.protocols.connections.v1_0.models.rst | 18 -- ...acapy_agent.protocols.connections.v1_0.rst | 44 --- docs/generated/acapy_agent.protocols.rst | 1 - docs/readthedocs.yaml | 2 +- docs/requirements.txt | 8 +- poetry.lock | 268 +----------------- pyproject.toml | 3 - 14 files changed, 29 insertions(+), 444 deletions(-) delete mode 100644 docs/generated/acapy_agent.protocols.connections.rst delete mode 100644 docs/generated/acapy_agent.protocols.connections.v1_0.handlers.rst delete mode 100644 docs/generated/acapy_agent.protocols.connections.v1_0.messages.rst delete mode 100644 docs/generated/acapy_agent.protocols.connections.v1_0.models.rst delete mode 100644 docs/generated/acapy_agent.protocols.connections.v1_0.rst diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 4865ff8187..8d19cd5bd0 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,7 +1,7 @@ version: 2 build: - os: "ubuntu-20.04" + os: "ubuntu-24.04" tools: python: "3.12" diff --git a/docs/UpdateRTD.md b/docs/UpdateRTD.md index ceabc1e7ac..1172244609 100644 --- a/docs/UpdateRTD.md +++ b/docs/UpdateRTD.md @@ -10,7 +10,11 @@ evolves, the RTD files need to be regenerated and possibly updated, as described To test generate and view the RTD documentation locally, you must install [Sphinx](https://www.sphinx-doc.org/en/master/) and the [Sphinx RTD theme](https://pypi.org/project/sphinx-rtd-theme/). Follow the instructions on the respective pages to install -and verify the installation on your system. +and verify the installation on your system. Alternatively, use pip to install it: + +``` bash +pip install -r docs/requirements.txt --upgrade +``` ### Generate Module Files diff --git a/docs/conf.py b/docs/conf.py index e81bb10889..48b79fdc62 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -254,9 +254,6 @@ # -- Extension configuration ------------------------------------------------- -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {"https://docs.python.org/": None} - # To supress cross-reference warnings # https://github.com/sphinx-doc/sphinx/issues/3866#issuecomment-768167824 diff --git a/docs/generated/acapy_agent.connections.rst b/docs/generated/acapy_agent.connections.rst index eb6ada146f..bd78244d74 100644 --- a/docs/generated/acapy_agent.connections.rst +++ b/docs/generated/acapy_agent.connections.rst @@ -24,3 +24,11 @@ acapy\_agent.connections.base\_manager module :members: :undoc-members: :show-inheritance: + +acapy\_agent.connections.routes module +-------------------------------------- + +.. automodule:: acapy_agent.connections.routes + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/generated/acapy_agent.protocols.connections.rst b/docs/generated/acapy_agent.protocols.connections.rst deleted file mode 100644 index 1c9769b59b..0000000000 --- a/docs/generated/acapy_agent.protocols.connections.rst +++ /dev/null @@ -1,26 +0,0 @@ -acapy\_agent.protocols.connections package -========================================== - -.. automodule:: acapy_agent.protocols.connections - :members: - :undoc-members: - :show-inheritance: - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - acapy_agent.protocols.connections.v1_0 - -Submodules ----------- - -acapy\_agent.protocols.connections.definition module ----------------------------------------------------- - -.. automodule:: acapy_agent.protocols.connections.definition - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/generated/acapy_agent.protocols.connections.v1_0.handlers.rst b/docs/generated/acapy_agent.protocols.connections.v1_0.handlers.rst deleted file mode 100644 index db6f608b5a..0000000000 --- a/docs/generated/acapy_agent.protocols.connections.v1_0.handlers.rst +++ /dev/null @@ -1,42 +0,0 @@ -acapy\_agent.protocols.connections.v1\_0.handlers package -========================================================= - -.. automodule:: acapy_agent.protocols.connections.v1_0.handlers - :members: - :undoc-members: - :show-inheritance: - -Submodules ----------- - -acapy\_agent.protocols.connections.v1\_0.handlers.connection\_invitation\_handler module ----------------------------------------------------------------------------------------- - -.. automodule:: acapy_agent.protocols.connections.v1_0.handlers.connection_invitation_handler - :members: - :undoc-members: - :show-inheritance: - -acapy\_agent.protocols.connections.v1\_0.handlers.connection\_request\_handler module -------------------------------------------------------------------------------------- - -.. automodule:: acapy_agent.protocols.connections.v1_0.handlers.connection_request_handler - :members: - :undoc-members: - :show-inheritance: - -acapy\_agent.protocols.connections.v1\_0.handlers.connection\_response\_handler module --------------------------------------------------------------------------------------- - -.. automodule:: acapy_agent.protocols.connections.v1_0.handlers.connection_response_handler - :members: - :undoc-members: - :show-inheritance: - -acapy\_agent.protocols.connections.v1\_0.handlers.problem\_report\_handler module ---------------------------------------------------------------------------------- - -.. automodule:: acapy_agent.protocols.connections.v1_0.handlers.problem_report_handler - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/generated/acapy_agent.protocols.connections.v1_0.messages.rst b/docs/generated/acapy_agent.protocols.connections.v1_0.messages.rst deleted file mode 100644 index a35a1f6755..0000000000 --- a/docs/generated/acapy_agent.protocols.connections.v1_0.messages.rst +++ /dev/null @@ -1,42 +0,0 @@ -acapy\_agent.protocols.connections.v1\_0.messages package -========================================================= - -.. automodule:: acapy_agent.protocols.connections.v1_0.messages - :members: - :undoc-members: - :show-inheritance: - -Submodules ----------- - -acapy\_agent.protocols.connections.v1\_0.messages.connection\_invitation module -------------------------------------------------------------------------------- - -.. automodule:: acapy_agent.protocols.connections.v1_0.messages.connection_invitation - :members: - :undoc-members: - :show-inheritance: - -acapy\_agent.protocols.connections.v1\_0.messages.connection\_request module ----------------------------------------------------------------------------- - -.. automodule:: acapy_agent.protocols.connections.v1_0.messages.connection_request - :members: - :undoc-members: - :show-inheritance: - -acapy\_agent.protocols.connections.v1\_0.messages.connection\_response module ------------------------------------------------------------------------------ - -.. automodule:: acapy_agent.protocols.connections.v1_0.messages.connection_response - :members: - :undoc-members: - :show-inheritance: - -acapy\_agent.protocols.connections.v1\_0.messages.problem\_report module ------------------------------------------------------------------------- - -.. automodule:: acapy_agent.protocols.connections.v1_0.messages.problem_report - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/generated/acapy_agent.protocols.connections.v1_0.models.rst b/docs/generated/acapy_agent.protocols.connections.v1_0.models.rst deleted file mode 100644 index c31d4d1a6f..0000000000 --- a/docs/generated/acapy_agent.protocols.connections.v1_0.models.rst +++ /dev/null @@ -1,18 +0,0 @@ -acapy\_agent.protocols.connections.v1\_0.models package -======================================================= - -.. automodule:: acapy_agent.protocols.connections.v1_0.models - :members: - :undoc-members: - :show-inheritance: - -Submodules ----------- - -acapy\_agent.protocols.connections.v1\_0.models.connection\_detail module -------------------------------------------------------------------------- - -.. automodule:: acapy_agent.protocols.connections.v1_0.models.connection_detail - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/generated/acapy_agent.protocols.connections.v1_0.rst b/docs/generated/acapy_agent.protocols.connections.v1_0.rst deleted file mode 100644 index 925f9d5b24..0000000000 --- a/docs/generated/acapy_agent.protocols.connections.v1_0.rst +++ /dev/null @@ -1,44 +0,0 @@ -acapy\_agent.protocols.connections.v1\_0 package -================================================ - -.. automodule:: acapy_agent.protocols.connections.v1_0 - :members: - :undoc-members: - :show-inheritance: - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - acapy_agent.protocols.connections.v1_0.handlers - acapy_agent.protocols.connections.v1_0.messages - acapy_agent.protocols.connections.v1_0.models - -Submodules ----------- - -acapy\_agent.protocols.connections.v1\_0.manager module -------------------------------------------------------- - -.. automodule:: acapy_agent.protocols.connections.v1_0.manager - :members: - :undoc-members: - :show-inheritance: - -acapy\_agent.protocols.connections.v1\_0.message\_types module --------------------------------------------------------------- - -.. automodule:: acapy_agent.protocols.connections.v1_0.message_types - :members: - :undoc-members: - :show-inheritance: - -acapy\_agent.protocols.connections.v1\_0.routes module ------------------------------------------------------- - -.. automodule:: acapy_agent.protocols.connections.v1_0.routes - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/generated/acapy_agent.protocols.rst b/docs/generated/acapy_agent.protocols.rst index 21c849bc6b..cf5b41a5cb 100644 --- a/docs/generated/acapy_agent.protocols.rst +++ b/docs/generated/acapy_agent.protocols.rst @@ -14,7 +14,6 @@ Subpackages acapy_agent.protocols.actionmenu acapy_agent.protocols.basicmessage - acapy_agent.protocols.connections acapy_agent.protocols.coordinate_mediation acapy_agent.protocols.did_rotate acapy_agent.protocols.didexchange diff --git a/docs/readthedocs.yaml b/docs/readthedocs.yaml index a1cdf7e435..a6e23de6e3 100644 --- a/docs/readthedocs.yaml +++ b/docs/readthedocs.yaml @@ -3,7 +3,7 @@ version: 2 build: - os: "ubuntu-20.04" + os: "ubuntu-24.04" tools: python: "3.12" diff --git a/docs/requirements.txt b/docs/requirements.txt index f03925f7c4..d78d51757e 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,5 +1,5 @@ # Defining the exact versions for ReadTheDocs that will make sure things don't break -sphinx==5.3.0 -sphinx_rtd_theme==1.3.0 -readthedocs-sphinx-search==0.3.2 -sphinx-notfound-page==1.1.0 +sphinx~=8.1.3 +sphinx-rtd-theme~=3.0.2 +readthedocs-sphinx-search~=0.3.2 +sphinx-notfound-page~=1.1.0 diff --git a/poetry.lock b/poetry.lock index e306d3256a..eb8c2ecd1a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -163,18 +163,6 @@ files = [ [package.dependencies] frozenlist = ">=1.1.0" -[[package]] -name = "alabaster" -version = "1.0.0" -description = "A light, configurable Sphinx theme" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b"}, - {file = "alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e"}, -] - [[package]] name = "annotated-types" version = "0.7.0" @@ -257,21 +245,6 @@ docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphi tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] -[[package]] -name = "babel" -version = "2.16.0" -description = "Internationalization utilities" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, - {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, -] - -[package.extras] -dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] - [[package]] name = "base58" version = "2.1.1" @@ -336,7 +309,7 @@ version = "2024.12.14" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" -groups = ["main", "dev"] +groups = ["main"] files = [ {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, @@ -440,7 +413,7 @@ version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" -groups = ["main", "dev"] +groups = ["main"] files = [ {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, @@ -654,6 +627,7 @@ files = [ {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:60eb32934076fa07e4316b7b2742fa52cbb190b42c2df2863dbc4230a0a9b385"}, {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e"}, {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e"}, {file = "cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053"}, @@ -664,6 +638,7 @@ files = [ {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9abcc2e083cbe8dde89124a47e5e53ec38751f0d7dfd36801008f316a127d7ba"}, {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64"}, {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285"}, {file = "cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417"}, @@ -946,18 +921,6 @@ files = [ {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, ] -[[package]] -name = "docutils" -version = "0.21.2" -description = "Docutils -- Python Documentation Utilities" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, - {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, -] - [[package]] name = "ecdsa" version = "0.19.0" @@ -1243,7 +1206,7 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" -groups = ["main", "dev"] +groups = ["main"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -1252,18 +1215,6 @@ files = [ [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] -[[package]] -name = "imagesize" -version = "1.4.1" -description = "Getting image size from png/jpeg/jpeg2000/gif file" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -groups = ["dev"] -files = [ - {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, - {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, -] - [[package]] name = "indy-credx" version = "1.1.1" @@ -1322,7 +1273,7 @@ version = "3.1.5" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" -groups = ["main", "dev"] +groups = ["main"] files = [ {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, @@ -1355,8 +1306,6 @@ python-versions = "*" groups = ["main"] files = [ {file = "jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c"}, - {file = "jsonpath_ng-1.7.0-py2-none-any.whl", hash = "sha256:898c93fc173f0c336784a3fa63d7434297544b7198124a68f9a3ef9597b0ae6e"}, - {file = "jsonpath_ng-1.7.0-py3-none-any.whl", hash = "sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6"}, ] [package.dependencies] @@ -1555,7 +1504,7 @@ version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" -groups = ["main", "dev"] +groups = ["main"] files = [ {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, @@ -2321,21 +2270,6 @@ inflection = ">=0.5.1,<0.6.0" pydantic = ">=2.7.0,<3.0.0" typing-extensions = ">=4.7.0,<5.0.0" -[[package]] -name = "pygments" -version = "2.19.1" -description = "Pygments is a syntax highlighting package written in Python." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, - {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, -] - -[package.extras] -windows-terminal = ["colorama (>=0.4.6)"] - [[package]] name = "pyjwt" version = "2.10.1" @@ -2649,7 +2583,7 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] +groups = ["main"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -2742,188 +2676,6 @@ files = [ {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] -[[package]] -name = "snowballstemmer" -version = "2.2.0" -description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." -optional = false -python-versions = "*" -groups = ["dev"] -files = [ - {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, - {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, -] - -[[package]] -name = "sphinx" -version = "8.1.3" -description = "Python documentation generator" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2"}, - {file = "sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927"}, -] - -[package.dependencies] -alabaster = ">=0.7.14" -babel = ">=2.13" -colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""} -docutils = ">=0.20,<0.22" -imagesize = ">=1.3" -Jinja2 = ">=3.1" -packaging = ">=23.0" -Pygments = ">=2.17" -requests = ">=2.30.0" -snowballstemmer = ">=2.2" -sphinxcontrib-applehelp = ">=1.0.7" -sphinxcontrib-devhelp = ">=1.0.6" -sphinxcontrib-htmlhelp = ">=2.0.6" -sphinxcontrib-jsmath = ">=1.0.1" -sphinxcontrib-qthelp = ">=1.0.6" -sphinxcontrib-serializinghtml = ">=1.1.9" - -[package.extras] -docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=6.0)", "mypy (==1.11.1)", "pyright (==1.1.384)", "pytest (>=6.0)", "ruff (==0.6.9)", "sphinx-lint (>=0.9)", "tomli (>=2)", "types-Pillow (==10.2.0.20240822)", "types-Pygments (==2.18.0.20240506)", "types-colorama (==0.4.15.20240311)", "types-defusedxml (==0.7.0.20240218)", "types-docutils (==0.21.0.20241005)", "types-requests (==2.32.0.20240914)", "types-urllib3 (==1.26.25.14)"] -test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] - -[[package]] -name = "sphinx-rtd-theme" -version = "3.0.2" -description = "Read the Docs theme for Sphinx" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl", hash = "sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13"}, - {file = "sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85"}, -] - -[package.dependencies] -docutils = ">0.18,<0.22" -sphinx = ">=6,<9" -sphinxcontrib-jquery = ">=4,<5" - -[package.extras] -dev = ["bump2version", "transifex-client", "twine", "wheel"] - -[[package]] -name = "sphinxcontrib-applehelp" -version = "2.0.0" -description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, - {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, -] - -[package.extras] -lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] -standalone = ["Sphinx (>=5)"] -test = ["pytest"] - -[[package]] -name = "sphinxcontrib-devhelp" -version = "2.0.0" -description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, - {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, -] - -[package.extras] -lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] -standalone = ["Sphinx (>=5)"] -test = ["pytest"] - -[[package]] -name = "sphinxcontrib-htmlhelp" -version = "2.1.0" -description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, - {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, -] - -[package.extras] -lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] -standalone = ["Sphinx (>=5)"] -test = ["html5lib", "pytest"] - -[[package]] -name = "sphinxcontrib-jquery" -version = "4.1" -description = "Extension to include jQuery on newer Sphinx releases" -optional = false -python-versions = ">=2.7" -groups = ["dev"] -files = [ - {file = "sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a"}, - {file = "sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae"}, -] - -[package.dependencies] -Sphinx = ">=1.8" - -[[package]] -name = "sphinxcontrib-jsmath" -version = "1.0.1" -description = "A sphinx extension which renders display math in HTML via JavaScript" -optional = false -python-versions = ">=3.5" -groups = ["dev"] -files = [ - {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, - {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, -] - -[package.extras] -test = ["flake8", "mypy", "pytest"] - -[[package]] -name = "sphinxcontrib-qthelp" -version = "2.0.0" -description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, - {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, -] - -[package.extras] -lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] -standalone = ["Sphinx (>=5)"] -test = ["defusedxml (>=0.7.1)", "pytest"] - -[[package]] -name = "sphinxcontrib-serializinghtml" -version = "2.0.0" -description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, - {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, -] - -[package.extras] -lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] -standalone = ["Sphinx (>=5)"] -test = ["pytest"] - [[package]] name = "toolz" version = "1.0.0" @@ -2982,7 +2734,7 @@ version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" -groups = ["main", "dev"] +groups = ["main"] files = [ {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, @@ -3204,4 +2956,4 @@ didcommv2 = ["didcomm-messaging"] [metadata] lock-version = "2.1" python-versions = "^3.12" -content-hash = "4af9f539695c21f944f8a499e732930999210466ecd1345f1c4741de288feaaa" +content-hash = "cc1de5dbba1f6550873d8aee9b7df0367ebe83606933cb92e341d5b523f47c3b" diff --git a/pyproject.toml b/pyproject.toml index 1c0419555e..8b2299d56d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,9 +74,6 @@ ruff = "~0.9.6" pre-commit = "~4.1.0" -sphinx = "^8.1.3" -sphinx-rtd-theme = "^3.0.2" - pydevd = "~3.3.0" pydevd-pycharm = "^251.17181.23" From 1cf891338be5f31a2d99d591c480304621c412d3 Mon Sep 17 00:00:00 2001 From: Yuki I <42908250+MonolithicMonk@users.noreply.github.com> Date: Tue, 18 Feb 2025 13:41:36 -0600 Subject: [PATCH 09/76] Create ReuseConnection.md (#3534) * Create ReuseConnection.md Document how developers can leverage acapy's reuse connection feature Signed-off-by: Yuki I <42908250+MonolithicMonk@users.noreply.github.com> * Update example events object to be consistent Signed-off-by: Yuki I --------- Signed-off-by: Yuki I <42908250+MonolithicMonk@users.noreply.github.com> Signed-off-by: Yuki I --- docs/features/ReuseConnection.md | 130 +++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 docs/features/ReuseConnection.md diff --git a/docs/features/ReuseConnection.md b/docs/features/ReuseConnection.md new file mode 100644 index 0000000000..79e5643cda --- /dev/null +++ b/docs/features/ReuseConnection.md @@ -0,0 +1,130 @@ +# Reusing Connections Between Agents + +Leverage ACA‑Py's Out‑of‑Band (OOB) protocol to reuse existing connections instead of creating new ones for every interaction. + +--- + +## Quick Start + +*For developers who want code now* + +### 1. Generate a Reusable Invitation + +Use the following API call to create an invitation that supports connection reuse. Note that the invitation must include a resolvable DID (e.g., `did:peer:2`) in its `services` field. This is achieved by setting the `use_did_method` parameter. + +```bash +curl -X POST 'http://your-agent-admin:8031/out-of-band/create-invitation?auto_accept=true&multi_use=true' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer YOUR_API_KEY' \ + -d '{ + "handshake_protocols": ["https://didcomm.org/didexchange/1.1"], + "protocol_version": "1.1", + "use_did_method": "did:peer:2" + }' +``` + +### 2. Verify the Response + +Ensure that the response contains a `services` array with a resolvable DID: + +```json +{ + "state": "initial", + "trace": false, + "invi_msg_id": "ffaf017e-3980-45b7-ad43-a90a609d6eaf", + "oob_id": "ed7cc3f6-62cd-4b53-9285-534c198a8476", + "invitation": { + "@type": "https://didcomm.org/out-of-band/1.1/invitation", + "@id": "ffaf017e-3980-45b7-ad43-a90a609d6eaf", + "label": "First invitation to Barry", + "imageUrl": "https://example-image.com", + "handshake_protocols": [ + "https://didcomm.org/didexchange/1.1" + ], + "services": [ + "did:peer:2.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7" + ] + }, + "invitation_url": "https://example-admin.com?oob=example-1-invite-encoded-url" +} +``` + +### 3. Reuse the Connection + +When an invitee scans subsequent invitations that contain the **same DID**, ACA‑Py automatically sends a `reuse` message instead of creating a new connection. + +--- + +## Key Concepts + +### What Enables Connection Reuse? + +1. **Resolvable DID** + - The invitation’s `services` array **must** include a resolvable DID (e.g., `did:peer:2` or `did:peer:4`), as specified by the `use_did_method` parameter. + - *Do not use inline or non‑resolvable DIDs (e.g., `did:key`).* + +2. **Consistent DID Across Invitations** + - The inviter (e.g., the issuer) must reuse the same resolvable DID in subsequent invitations where reuse is desired. This consistency is enforced by setting `use_did_method` to `did:peer:2` (or `did:peer:4`) in the API call. + +3. **Protocol Version** + - Use `didexchange/1.1` (avoid the legacy `1.0`). + +#### Critical API Parameters + +| Parameter | Description | +|----------------------|------------------------------------------------------------------| +| `use_did_method` | Set to `did:peer:2` or `did:peer:4` (required for reuse). | +| `multi_use` | Optional but recommended for enabling multi‑use invitations. | +| `handshake_protocols`| Must include `https://didcomm.org/didexchange/1.1`. | + +--- + +## Handling Reuse Events + +When a connection is reused, ACA-Py automatically emits an event notification. This event contains the `connection_id` of the reused connection, allowing applications to track reuse activity programmatically. + +### Example Event Notification + +```json +{ + "thread_id": "096cf986-9211-450c-9cbb-a6d701c4d9ca", + "connection_id": "28818825-98a3-44c7-b1cc-d429c1583a1d", + "comment": "Connection 28818825-98a3-44c7-b1cc-d429c1583a1d is being reused for invitation 6f6af313-3735-4ac1-b972-aafebd3731bc" +} +``` + +### Listening for Reuse Events + +Applications can subscribe to these events via the WebSocket or webhooks event stream provided by ACA-Py. To listen for reuse events: + +1. Connect to the ACA-Py WebSocket server or setup a webhook endpoint. +2. Filter events with `type=connection_reuse`. +3. Handle the event in your application logic. + +--- + +## Troubleshooting + +| **Symptom** | **Likely Cause** | **Solution** | +|--------------------------------------------|--------------------------------------------|---------------------------------------------------------------------------------------| +| New connection created instead of reused | Invitation uses a non‑resolvable DID, `use_did_method` not set | Set `use_did_method=did:peer:2` (or `did:peer:4`) in the `/out-of-band/create-invitation` call. | +| `reuse` message not sent | Invitee agent doesn’t support OOB v1.1 | Ensure both agents are using `didexchange/1.1`. | +| DID resolution failed | The resolver does not support the chosen DID | Configure a DID resolver that supports the selected peer DID method. | + +--- + +## Demo vs. Production + +| **Scenario** | **Approach** | +|--------------|------------------------------------------------------------------------------| +| **Demo** | Use CLI flags such as `--reuse-connections`. | +| **Production**| Rely on API parameters (`use_did_method`, `multi_use`) for reuse events. | + +--- + +**Contributor Note:** +Tested with BC Wallet & Hologram apps. Reuse functionality has been confirmed to work with `did:peer:2` (see [Issue #3532](https://github.com/hyperledger/aries-cloudagent-python/issues/3532)). + +For more information on Qualified DIDs (e.g., `did:peer:2`, `did:peer:4`), visit the [Qualified DIDs Documentation](https://aca-py.org/latest/features/QualifiedDIDs/). + From 313535b2b3d55225ba7f6623ecffc92a0e8bda06 Mon Sep 17 00:00:00 2001 From: Stephen Curran Date: Tue, 18 Feb 2025 12:30:10 -0800 Subject: [PATCH 10/76] Add reuse document to MkDocs YML to add to doc site (#3535) Signed-off-by: Stephen Curran --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index cebeffcc7e..570180b6a9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -93,6 +93,7 @@ nav: - Qualified DIDs: features/QualifiedDIDs.md - DID Methods: features/DIDMethods.md - DID Resolution: features/DIDResolution.md + - Reusing DIDComm Connections Between Agents: features/ReuseConnection.md - Publishing AnonCreds Objects To Other Ledgers/Verifiable Data Registries: features/AnonCredsMethods.md - Configuring Multiple Indy Ledgers: features/Multiledger.md - Automatically Endorsing Indy Transations: features/Endorser.md From 4b8862ed7466f1fce22ea63be6ea672499e9c058 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Feb 2025 10:00:30 +0000 Subject: [PATCH 11/76] chore(deps): Bump pytest-asyncio in /demo/playground/examples (#3533) --- demo/playground/examples/poetry.lock | 30 ++++++++----------------- demo/playground/examples/pyproject.toml | 2 +- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/demo/playground/examples/poetry.lock b/demo/playground/examples/poetry.lock index 96749e1948..7b4a867c7e 100644 --- a/demo/playground/examples/poetry.lock +++ b/demo/playground/examples/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "certifi" @@ -6,7 +6,6 @@ version = "2025.1.31" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" -groups = ["main"] files = [ {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, @@ -18,7 +17,6 @@ version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, @@ -120,8 +118,6 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main"] -markers = "sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -133,7 +129,6 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" -groups = ["main"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -148,7 +143,6 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -160,7 +154,6 @@ version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, @@ -172,7 +165,6 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -188,7 +180,6 @@ version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, @@ -205,21 +196,20 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments [[package]] name = "pytest-asyncio" -version = "0.23.8" +version = "0.25.3" description = "Pytest support for asyncio" optional = false -python-versions = ">=3.8" -groups = ["main"] +python-versions = ">=3.9" files = [ - {file = "pytest_asyncio-0.23.8-py3-none-any.whl", hash = "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2"}, - {file = "pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3"}, + {file = "pytest_asyncio-0.25.3-py3-none-any.whl", hash = "sha256:9e89518e0f9bd08928f97a3482fdc4e244df17529460bc038291ccaf8f85c7c3"}, + {file = "pytest_asyncio-0.25.3.tar.gz", hash = "sha256:fc1da2cf9f125ada7e710b4ddad05518d4cee187ae9412e9ac9271003497f07a"}, ] [package.dependencies] -pytest = ">=7.0.0,<9" +pytest = ">=8.2,<9" [package.extras] -docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)"] testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] [[package]] @@ -228,7 +218,6 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -250,7 +239,6 @@ version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, @@ -263,6 +251,6 @@ socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [metadata] -lock-version = "2.1" +lock-version = "2.0" python-versions = "^3.12" -content-hash = "3d25008515cd2a124d4b920fd61465d2ac24634e0646cbc5851100af2c3a49ad" +content-hash = "6aa7dd5266368b13c5fbe3336506288281e262f4dac274d990b3809764ced9e0" diff --git a/demo/playground/examples/pyproject.toml b/demo/playground/examples/pyproject.toml index a283133e33..cd646a934c 100644 --- a/demo/playground/examples/pyproject.toml +++ b/demo/playground/examples/pyproject.toml @@ -8,7 +8,7 @@ package-mode=false [tool.poetry.dependencies] python = "^3.12" pytest = "^8.3.4" -pytest-asyncio = "^0.23.8" +pytest-asyncio = "^0.25.3" requests = "^2.32.3" [build-system] From 7c73d981866457f69b8737252c0185d83f0e71fe Mon Sep 17 00:00:00 2001 From: jamshale <31809382+jamshale@users.noreply.github.com> Date: Fri, 21 Feb 2025 09:30:24 -0800 Subject: [PATCH 12/76] Add did:indy transaction version 2 support (#3253) * Add did:indy support Signed-off-by: jamshale * Update from review comments Signed-off-by: jamshale * Some refactoring and cleanup from comments Signed-off-by: jamshale --------- Signed-off-by: jamshale Co-authored-by: Stephen Curran --- acapy_agent/config/default_context.py | 3 + acapy_agent/config/tests/test_wallet.py | 3 +- acapy_agent/config/wallet.py | 222 +++++++++++------- acapy_agent/did/indy/indy_manager.py | 87 +++++++ acapy_agent/did/indy/routes.py | 91 +++++++ .../did/indy/tests/test_indy_manager.py | 78 ++++++ acapy_agent/did/indy/tests/test_routes.py | 73 ++++++ acapy_agent/indy/credx/issuer.py | 10 +- acapy_agent/ledger/base.py | 9 +- acapy_agent/ledger/indy_vdr.py | 27 ++- acapy_agent/messaging/valid.py | 4 +- acapy_agent/revocation/indy.py | 13 +- acapy_agent/revocation/tests/test_indy.py | 3 +- acapy_agent/utils/general.py | 7 + acapy_agent/wallet/askar.py | 10 +- acapy_agent/wallet/base.py | 2 +- acapy_agent/wallet/crypto.py | 15 +- acapy_agent/wallet/did_method.py | 7 + .../wallet/did_parameters_validation.py | 4 + acapy_agent/wallet/routes.py | 7 + acapy_agent/wallet/tests/test_askar.py | 51 ++++ acapy_agent/wallet/tests/test_routes.py | 7 + .../docker-compose.yml | 89 +++++++ .../example.py | 122 ++++++++++ 24 files changed, 825 insertions(+), 119 deletions(-) create mode 100644 acapy_agent/did/indy/indy_manager.py create mode 100644 acapy_agent/did/indy/routes.py create mode 100644 acapy_agent/did/indy/tests/test_indy_manager.py create mode 100644 acapy_agent/did/indy/tests/test_routes.py create mode 100644 acapy_agent/wallet/tests/test_askar.py create mode 100644 scenarios/examples/did_indy_issuance_and_revocation/docker-compose.yml create mode 100644 scenarios/examples/did_indy_issuance_and_revocation/example.py diff --git a/acapy_agent/config/default_context.py b/acapy_agent/config/default_context.py index f405a5e807..22a3b021da 100644 --- a/acapy_agent/config/default_context.py +++ b/acapy_agent/config/default_context.py @@ -151,6 +151,9 @@ async def load_plugins(self, context: InjectionContext): plugin_registry.register_plugin("acapy_agent.wallet") plugin_registry.register_plugin("acapy_agent.wallet.keys") + # Did management plugins + plugin_registry.register_plugin("acapy_agent.did.indy") + anoncreds_plugins = [ "acapy_agent.anoncreds", "acapy_agent.anoncreds.default.did_indy", diff --git a/acapy_agent/config/tests/test_wallet.py b/acapy_agent/config/tests/test_wallet.py index 6f360dcf06..37d35d0025 100644 --- a/acapy_agent/config/tests/test_wallet.py +++ b/acapy_agent/config/tests/test_wallet.py @@ -1,5 +1,6 @@ from unittest import IsolatedAsyncioTestCase +from ...core.error import StartupError from ...core.profile import ProfileManager, ProfileSession from ...storage.base import BaseStorage from ...storage.record import StorageRecord @@ -149,7 +150,7 @@ async def test_wallet_config_auto_provision(self): ): mock_mgr_open.side_effect = test_module.ProfileNotFoundError() - with self.assertRaises(test_module.ProfileNotFoundError): + with self.assertRaises(StartupError): await test_module.wallet_config(self.context, provision=False) self.context.update_settings({"auto_provision": True}) diff --git a/acapy_agent/config/wallet.py b/acapy_agent/config/wallet.py index ce5beb8fc3..db5a3b662a 100644 --- a/acapy_agent/config/wallet.py +++ b/acapy_agent/config/wallet.py @@ -3,7 +3,7 @@ import logging from typing import Tuple -from ..core.error import ProfileNotFoundError +from ..core.error import ProfileNotFoundError, StartupError from ..core.profile import Profile, ProfileManager, ProfileSession from ..storage.base import BaseStorage from ..storage.error import StorageNotFoundError @@ -30,104 +30,84 @@ } -async def wallet_config( - context: InjectionContext, provision: bool = False -) -> Tuple[Profile, DIDInfo]: - """Initialize the root profile.""" +def _create_config_with_settings(settings) -> dict: + profile_config = {} - mgr = context.inject(ProfileManager) - - settings = context.settings - profile_cfg = {} for k in CFG_MAP: pk = f"wallet.{k}" if pk in settings: - profile_cfg[k] = settings[pk] + profile_config[k] = settings[pk] # may be set by `aca-py provision --recreate` if settings.get("wallet.recreate"): - profile_cfg["auto_recreate"] = True + profile_config["auto_recreate"] = True - if provision: - profile = await mgr.provision(context, profile_cfg) - else: - try: - profile = await mgr.open(context, profile_cfg) - except ProfileNotFoundError: - if settings.get("auto_provision", False): - profile = await mgr.provision(context, profile_cfg) - provision = True - else: - raise + return profile_config - if provision: - if profile.created: - print("Created new profile") + +async def _attempt_open_profile( + profile_manager: ProfileManager, + context: InjectionContext, + profile_config: dict, + settings: dict, +) -> Tuple[Profile, bool]: + provision = False + try: + profile = await profile_manager.open(context, profile_config) + except ProfileNotFoundError: + if settings.get("auto_provision", False): + profile = await profile_manager.provision(context, profile_config) + provision = True else: - print("Opened existing profile") - print("Profile backend:", profile.backend) - print("Profile name:", profile.name) + error_msg = ( + "Profile not found. Use `aca-py start --auto-provision` to create." + ) + LOGGER.error(error_msg) + raise StartupError(error_msg) + + return (profile, provision) + + +def _log_provision_info(profile: Profile) -> None: + LOGGER.info( + "Created new profile - " + if profile.created + else "Opened existing profile - " + f"Profile name: {profile.name}, backend: {profile.backend}" + ) + + +async def _initialize_with_public_did( + public_did_info: DIDInfo, + wallet: BaseWallet, + settings: dict, + wallet_seed: str, +) -> str: + public_did = public_did_info.did + # Check did:sov seed matches public DID + if wallet_seed and (seed_to_did(wallet_seed) != public_did): + if not settings.get("wallet.replace_public_did"): + raise ConfigError( + "New seed provided which doesn't match the registered" + + f" public did {public_did}" + ) - wallet_seed = context.settings.get("wallet.seed") - wallet_local_did = context.settings.get("wallet.local_did") - txn = await profile.transaction() - wallet = txn.inject(BaseWallet) + LOGGER.info("Replacing public DID due to --replace-public-did flag") + replace_did_info = await wallet.create_local_did( + method=SOV, key_type=ED25519, seed=wallet_seed + ) + public_did = replace_did_info.did + await wallet.set_public_did(public_did) + LOGGER.info( + f"Created new public DID: {public_did}, " + f"with verkey: {replace_did_info.verkey}" + ) - public_did_info = await wallet.get_public_did() - public_did = None - if public_did_info: - public_did = public_did_info.did - if wallet_seed and seed_to_did(wallet_seed) != public_did: - if context.settings.get("wallet.replace_public_did"): - replace_did_info = await wallet.create_local_did( - method=SOV, key_type=ED25519, seed=wallet_seed - ) - public_did = replace_did_info.did - await wallet.set_public_did(public_did) - print(f"Created new public DID: {public_did}") - print(f"Verkey: {replace_did_info.verkey}") - else: - # If we already have a registered public did and it doesn't match - # the one derived from `wallet_seed` then we error out. - raise ConfigError( - "New seed provided which doesn't match the registered" - + f" public did {public_did}" - ) - # wait until ledger config to set public DID endpoint - wallet goes first - elif wallet_seed: - if wallet_local_did: - endpoint = context.settings.get("default_endpoint") - metadata = {"endpoint": endpoint} if endpoint else None - - local_did_info = await wallet.create_local_did( - method=SOV, - key_type=ED25519, - seed=wallet_seed, - metadata=metadata, - ) - local_did = local_did_info.did - if provision: - print(f"Created new local DID: {local_did}") - print(f"Verkey: {local_did_info.verkey}") - else: - public_did_info = await wallet.create_public_did( - method=SOV, key_type=ED25519, seed=wallet_seed - ) - public_did = public_did_info.did - if provision: - print(f"Created new public DID: {public_did}") - print(f"Verkey: {public_did_info.verkey}") - # wait until ledger config to set public DID endpoint - wallet goes first - - if provision and not wallet_local_did and not public_did: - print("No public DID") - - # Debug settings - test_seed = context.settings.get("debug.seed") - if context.settings.get("debug.enabled"): - if not test_seed: - test_seed = "testseed000000000000000000000001" +async def _initialize_with_debug_settings(settings: dict, wallet: BaseWallet): + test_seed = settings.get("debug.seed") + if settings.get("debug.enabled") and not test_seed: + test_seed = "testseed000000000000000000000001" if test_seed: await wallet.create_local_did( method=SOV, @@ -136,6 +116,76 @@ async def wallet_config( metadata={"endpoint": "1.2.3.4:8021"}, ) + +async def _initialize_with_seed( + settings: dict, wallet: BaseWallet, provision: bool, create_local_did: bool, seed: str +): + def _log_did_info(did: str, verkey: str, is_public: bool): + LOGGER.info( + f"Created new {'public' if is_public else 'local'}" + f"DID: {did}, Verkey: {verkey}" + ) + + if create_local_did: + endpoint = settings.get("default_endpoint") + metadata = {"endpoint": endpoint} if endpoint else None + + local_did_info = await wallet.create_local_did( + method=SOV, + key_type=ED25519, + seed=seed, + metadata=metadata, + ) + local_did = local_did_info.did + _log_did_info(local_did, local_did_info.verkey, False) + else: + public_did_info = await wallet.create_public_did( + method=SOV, key_type=ED25519, seed=seed + ) + public_did = public_did_info.did + _log_did_info(public_did, public_did_info.verkey, True) + + +async def wallet_config( + context: InjectionContext, provision: bool = False +) -> Tuple[Profile, DIDInfo]: + """Initialize the root profile.""" + + profile_manager = context.inject(ProfileManager) + + settings = context.settings + profile_config = _create_config_with_settings(settings) + wallet_seed = settings.get("wallet.seed") + create_local_did = settings.get("wallet.local_did") + + if provision: + profile = await profile_manager.provision(context, profile_config) + else: + profile, provision = await _attempt_open_profile( + profile_manager, context, profile_config, settings + ) + + _log_provision_info(profile) + + txn = await profile.transaction() + wallet = txn.inject(BaseWallet) + public_did_info = await wallet.get_public_did() + public_did = None + + if public_did_info: + public_did = await _initialize_with_public_did( + public_did_info, wallet, settings, wallet_seed + ) + elif wallet_seed: + await _initialize_with_seed( + settings, wallet, provision, create_local_did, wallet_seed + ) + + if provision and not create_local_did and not public_did: + LOGGER.info("No public DID") + + await _initialize_with_debug_settings(settings, wallet) + await txn.commit() return (profile, public_did_info) diff --git a/acapy_agent/did/indy/indy_manager.py b/acapy_agent/did/indy/indy_manager.py new file mode 100644 index 0000000000..c745f51835 --- /dev/null +++ b/acapy_agent/did/indy/indy_manager.py @@ -0,0 +1,87 @@ +"""DID manager for Indy.""" + +from aries_askar import AskarError, Key + +from ...core.profile import Profile +from ...utils.general import strip_did_prefix +from ...wallet.askar import CATEGORY_DID +from ...wallet.crypto import validate_seed +from ...wallet.did_method import INDY, DIDMethods +from ...wallet.did_parameters_validation import DIDParametersValidation +from ...wallet.error import WalletError +from ...wallet.key_type import ED25519, KeyType, KeyTypes +from ...wallet.util import bytes_to_b58 + + +class DidIndyManager: + """DID manager for Indy.""" + + def __init__(self, profile: Profile) -> None: + """Initialize the DID manager.""" + self.profile = profile + + async def _get_holder_defined_did(self, options: dict) -> str | None: + async with self.profile.session() as session: + did_methods = session.inject(DIDMethods) + indy_method = did_methods.from_method(INDY.method_name) + + if indy_method.holder_defined_did() and options.get("did"): + return strip_did_prefix(options.get("did")) + + return None + + async def _get_key_type(self, key_type: str) -> KeyType: + async with self.profile.session() as session: + key_types = session.inject(KeyTypes) + return key_types.from_key_type(key_type) or ED25519 + + def _create_key_pair(self, options: dict, key_type: KeyType) -> Key: + seed = options.get("seed") + if seed: + seed = validate_seed(seed) + return Key.from_secret_bytes(key_type, seed) + return Key.generate(key_type) + + async def register(self, options: dict) -> dict: + """Register a DID Indy.""" + options = options or {} + + key_type = await self._get_key_type(options.get("key_type") or ED25519) + did_validation = DIDParametersValidation(self.profile.inject(DIDMethods)) + did_validation.validate_key_type(INDY, key_type) + + key_pair = self._create_key_pair(options, key_type.key_type) + verkey_bytes = key_pair.get_public_bytes() + verkey = bytes_to_b58(verkey_bytes) + + nym = did_validation.validate_or_derive_did( + INDY, ED25519, verkey_bytes, (await self._get_holder_defined_did(options)) + ) + did = f"did:indy:{nym}" + + async with self.profile.session() as session: + try: + await session.handle.insert_key(verkey, key_pair) + await session.handle.insert( + CATEGORY_DID, + did, + value_json={ + "did": did, + "method": INDY.method_name, + "verkey": verkey, + "verkey_type": ED25519.key_type, + "metadata": {}, + }, + tags={ + "method": INDY.method_name, + "verkey": verkey, + "verkey_type": ED25519.key_type, + }, + ) + except AskarError as err: + raise WalletError(f"Error registering DID: {err}") from err + + return { + "did": did, + "verkey": verkey, + } diff --git a/acapy_agent/did/indy/routes.py b/acapy_agent/did/indy/routes.py new file mode 100644 index 0000000000..cae5e0c7ad --- /dev/null +++ b/acapy_agent/did/indy/routes.py @@ -0,0 +1,91 @@ +"""DID INDY routes.""" + +from http import HTTPStatus + +from aiohttp import web +from aiohttp_apispec import docs, request_schema, response_schema +from marshmallow import fields + +from ...admin.decorators.auth import tenant_authentication +from ...admin.request_context import AdminRequestContext +from ...did.indy.indy_manager import DidIndyManager +from ...messaging.models.openapi import OpenAPISchema +from ...wallet.error import WalletError + + +class CreateRequestSchema(OpenAPISchema): + """Parameters and validators for create DID endpoint.""" + + options = fields.Dict( + required=False, + metadata={ + "description": "Additional configuration options", + "example": { + "did": "did:indy:WRfXPg8dantKVubE3HX8pw", + "seed": "000000000000000000000000Trustee1", + "key_type": "ed25519", + }, + }, + ) + features = fields.Dict( + required=False, + metadata={ + "description": "Additional features to enable for the did.", + "example": "{}", + }, + ) + + +class CreateResponseSchema(OpenAPISchema): + """Response schema for create DID endpoint.""" + + did = fields.Str( + metadata={ + "description": "DID created", + "example": "did:indy:DFZgMggBEXcZFVQ2ZBTwdr", + } + ) + verkey = fields.Str( + metadata={ + "description": "Verification key", + "example": "BnSWTUQmdYCewSGFrRUhT6LmKdcCcSzRGqWXMPnEP168", + } + ) + + +@docs(tags=["did"], summary="Create a did:indy") +@request_schema(CreateRequestSchema()) +@response_schema(CreateResponseSchema, HTTPStatus.OK) +@tenant_authentication +async def create_indy_did(request: web.BaseRequest): + """Create a INDY DID.""" + context: AdminRequestContext = request["context"] + body = await request.json() + try: + return web.json_response( + (await DidIndyManager(context.profile).register(body.get("options"))), + ) + except WalletError as e: + raise web.HTTPBadRequest(reason=str(e)) + + +async def register(app: web.Application): + """Register routes.""" + app.add_routes([web.post("/did/indy/create", create_indy_did)]) + + +def post_process_routes(app: web.Application): + """Amend swagger API.""" + # Add top-level tags description + if "tags" not in app._state["swagger_dict"]: + app._state["swagger_dict"]["tags"] = [] + app._state["swagger_dict"]["tags"].append( + { + "name": "did", + "description": "Endpoints for managing dids", + "externalDocs": { + "description": "Specification", + "url": "https://www.w3.org/TR/did-core/", + }, + } + ) diff --git a/acapy_agent/did/indy/tests/test_indy_manager.py b/acapy_agent/did/indy/tests/test_indy_manager.py new file mode 100644 index 0000000000..784df10736 --- /dev/null +++ b/acapy_agent/did/indy/tests/test_indy_manager.py @@ -0,0 +1,78 @@ +from unittest import IsolatedAsyncioTestCase + +from aries_askar import AskarError + +from acapy_agent.askar.profile import AskarProfileSession +from acapy_agent.did.indy.indy_manager import DidIndyManager +from acapy_agent.tests import mock +from acapy_agent.utils.testing import create_test_profile +from acapy_agent.wallet.did_method import DIDMethods +from acapy_agent.wallet.error import WalletError +from acapy_agent.wallet.key_type import KeyTypes + + +class TestIndyManager(IsolatedAsyncioTestCase): + async def asyncSetUp(self) -> None: + self.profile = await create_test_profile() + self.profile.context.injector.bind_instance( + DIDMethods, mock.MagicMock(DIDMethods, auto_spec=True) + ) + self.profile.context.injector.bind_instance(KeyTypes, KeyTypes()) + + def test_init(self): + assert DidIndyManager(self.profile) + + @mock.patch.object(AskarProfileSession, "handle") + async def test_register(self, mock_handle): + mock_handle.insert_key = mock.CoroutineMock() + mock_handle.insert = mock.CoroutineMock() + manager = DidIndyManager(self.profile) + result = await manager.register({}) + assert result.get("did") + assert result.get("verkey") + mock_handle.insert_key.assert_called_once() + mock_handle.insert.assert_called_once() + + # error saving key + mock_handle.insert_key.side_effect = AskarError( + code=1, message="Error saving key" + ) + with self.assertRaises(WalletError): + await manager.register({}) + + @mock.patch.object(AskarProfileSession, "handle") + async def test_register_with_seed_with_key_type(self, mock_handle): + mock_handle.insert_key = mock.CoroutineMock() + mock_handle.insert = mock.CoroutineMock() + manager = DidIndyManager(self.profile) + + result = await manager.register({"key_type": "ed25519"}) + assert result.get("did") + assert result.get("verkey") + + @mock.patch.object(AskarProfileSession, "handle") + async def test_register_with_seed_with_defined_did(self, mock_handle): + mock_handle.insert_key = mock.CoroutineMock() + mock_handle.insert = mock.CoroutineMock() + manager = DidIndyManager(self.profile) + + result = await manager.register({"did": "did:indy:WRfXPg8dantKVubE3HX8pw"}) + assert result.get("did") == "did:indy:WRfXPg8dantKVubE3HX8pw" + assert result.get("verkey") + + @mock.patch.object(AskarProfileSession, "handle") + async def test_register_with_seed_with_all_options(self, mock_handle): + self.profile.settings.set_value("wallet.allow_insecure_seed", True) + mock_handle.insert_key = mock.CoroutineMock() + mock_handle.insert = mock.CoroutineMock() + manager = DidIndyManager(self.profile) + + result = await manager.register( + { + "did": "did:indy:WRfXPg8dantKVubE3HX8pw", + "key_type": "ed25519", + "seed": "000000000000000000000000Trustee1", + } + ) + assert result.get("did") == "did:indy:WRfXPg8dantKVubE3HX8pw" + assert result.get("verkey") diff --git a/acapy_agent/did/indy/tests/test_routes.py b/acapy_agent/did/indy/tests/test_routes.py new file mode 100644 index 0000000000..156e4db693 --- /dev/null +++ b/acapy_agent/did/indy/tests/test_routes.py @@ -0,0 +1,73 @@ +from unittest import IsolatedAsyncioTestCase + +from aiohttp import web + +from acapy_agent.admin.request_context import AdminRequestContext +from acapy_agent.did.indy.indy_manager import DidIndyManager +from acapy_agent.did.indy.routes import create_indy_did +from acapy_agent.tests import mock +from acapy_agent.utils.testing import create_test_profile +from acapy_agent.wallet.did_method import DIDMethods +from acapy_agent.wallet.error import WalletError + + +class TestDidIndyRoutes(IsolatedAsyncioTestCase): + async def asyncSetUp(self) -> None: + self.session_inject = {} + self.profile = await create_test_profile( + settings={ + "admin.admin_api_key": "secret-key", + }, + ) + self.context = AdminRequestContext.test_context(self.session_inject, self.profile) + self.request_dict = { + "context": self.context, + } + self.request = mock.MagicMock( + app={}, + match_info={}, + query={}, + __getitem__=lambda _, k: self.request_dict[k], + context=self.context, + headers={"x-api-key": "secret-key"}, + ) + + @mock.patch.object( + DidIndyManager, + "register", + return_value={"did": "did:indy:DFZgMggBEXcZFVQ2ZBTwdr", "verkey": "BnSWTUQmdYC"}, + ) + async def test_create_indy_did(self, mock_register): + self.profile.context.injector.bind_instance( + DIDMethods, mock.MagicMock(DIDMethods, auto_spec=True) + ) + self.request.json = mock.CoroutineMock(return_value={}) + response = await create_indy_did(self.request) + assert response.status == 200 + assert mock_register.called + + self.request.json = mock.CoroutineMock( + return_value={ + "features": {}, + "options": { + "did": "did:indy:WRfXPg8dantKVubE3HX8pw", + "key_type": "ed25519", + }, + } + ) + response = await create_indy_did(self.request) + assert response.status == 200 + assert mock_register.called + + @mock.patch.object( + DidIndyManager, + "register", + side_effect=[WalletError("Error creating DID")], + ) + async def test_create_indy_did_wallet_error(self, _): + self.profile.context.injector.bind_instance( + DIDMethods, mock.MagicMock(DIDMethods, auto_spec=True) + ) + self.request.json = mock.CoroutineMock(return_value={}) + with self.assertRaises(web.HTTPBadRequest): + await create_indy_did(self.request) diff --git a/acapy_agent/indy/credx/issuer.py b/acapy_agent/indy/credx/issuer.py index c67b4d911a..4dc09c2ba2 100644 --- a/acapy_agent/indy/credx/issuer.py +++ b/acapy_agent/indy/credx/issuer.py @@ -19,6 +19,7 @@ ) from ...askar.profile import AskarProfile +from ...utils.general import strip_did_prefix from ..issuer import ( DEFAULT_CRED_DEF_TAG, DEFAULT_SIGNATURE_TYPE, @@ -78,7 +79,10 @@ async def create_schema( """ try: schema = Schema.create( - origin_did, schema_name, schema_version, attribute_names + strip_did_prefix(origin_did), + schema_name, + schema_version, + attribute_names, ) schema_id = schema.id schema_json = schema.to_json() @@ -143,7 +147,7 @@ async def create_and_store_credential_definition( ) = await asyncio.get_event_loop().run_in_executor( None, lambda: CredentialDefinition.create( - origin_did, + strip_did_prefix(origin_did), schema, signature_type or DEFAULT_SIGNATURE_TYPE, tag or DEFAULT_CRED_DEF_TAG, @@ -597,7 +601,7 @@ async def create_and_store_revocation_registry( ) = await asyncio.get_event_loop().run_in_executor( None, lambda: RevocationRegistryDefinition.create( - origin_did, + strip_did_prefix(origin_did), cred_def.raw_value, tag, revoc_def_type, diff --git a/acapy_agent/ledger/base.py b/acapy_agent/ledger/base.py index 576d591a0a..20ed0718fa 100644 --- a/acapy_agent/ledger/base.py +++ b/acapy_agent/ledger/base.py @@ -2,7 +2,6 @@ import json import logging -import re from abc import ABC, ABCMeta, abstractmethod from enum import Enum from hashlib import sha256 @@ -11,6 +10,7 @@ from ..indy.issuer import DEFAULT_CRED_DEF_TAG, IndyIssuer, IndyIssuerError from ..messaging.valid import IndyDID from ..utils import sentinel +from ..utils.general import strip_did_prefix from ..wallet.did_info import DIDInfo from .endpoint_type import EndpointType from .error import ( @@ -174,11 +174,6 @@ async def rotate_public_did_keypair(self, next_seed: Optional[str] = None) -> No next_seed: seed for incoming ed25519 keypair (default random) """ - def did_to_nym(self, did: str) -> str: - """Remove the ledger's DID prefix to produce a nym.""" - if did: - return re.sub(r"^did:\w+:", "", did) - @abstractmethod async def get_wallet_public_did(self) -> DIDInfo: """Fetch the public DID from the wallet.""" @@ -462,7 +457,7 @@ async def create_and_send_credential_definition( # check if cred def is on ledger already for test_tag in [tag] if tag else ["tag", DEFAULT_CRED_DEF_TAG]: credential_definition_id = issuer.make_credential_definition_id( - public_info.did, schema, signature_type, test_tag + strip_did_prefix(public_info.did), schema, signature_type, test_tag ) ledger_cred_def = await self.fetch_credential_definition( credential_definition_id diff --git a/acapy_agent/ledger/indy_vdr.py b/acapy_agent/ledger/indy_vdr.py index 5a9b7a2ba0..77ee86a898 100644 --- a/acapy_agent/ledger/indy_vdr.py +++ b/acapy_agent/ledger/indy_vdr.py @@ -21,6 +21,7 @@ from ..storage.base import BaseStorage, StorageRecord from ..utils import sentinel from ..utils.env import storage_path +from ..utils.general import strip_did_prefix from ..wallet.base import BaseWallet, DIDInfo from ..wallet.did_posture import DIDPosture from ..wallet.error import WalletNotFoundError @@ -379,7 +380,9 @@ async def _create_schema_request( ): """Create the ledger request for publishing a schema.""" try: - schema_req = ledger.build_schema_request(public_info.did, schema_json) + schema_req = ledger.build_schema_request( + strip_did_prefix(public_info.did), schema_json + ) except VdrError as err: raise LedgerError("Exception when building schema request") from err @@ -462,7 +465,9 @@ async def fetch_schema_by_id(self, schema_id: str) -> dict: public_did = public_info.did if public_info else None try: - schema_req = ledger.build_get_schema_request(public_did, schema_id) + schema_req = ledger.build_get_schema_request( + strip_did_prefix(public_did), strip_did_prefix(schema_id) + ) except VdrError as err: raise LedgerError("Exception when building get-schema request") from err @@ -568,7 +573,9 @@ async def get_credential_definition(self, credential_definition_id: str) -> dict return await self.fetch_credential_definition(credential_definition_id) - async def fetch_credential_definition(self, credential_definition_id: str) -> dict: + async def fetch_credential_definition( + self, credential_definition_id: str + ) -> dict | None: """Get a credential definition from the ledger by id. Args: @@ -581,7 +588,7 @@ async def fetch_credential_definition(self, credential_definition_id: str) -> di try: cred_def_req = ledger.build_get_cred_def_request( - public_did, credential_definition_id + strip_did_prefix(public_did), strip_did_prefix(credential_definition_id) ) except VdrError as err: raise LedgerError("Exception when building get-cred-def request") from err @@ -630,7 +637,7 @@ async def get_key_for_did(self, did: str) -> Optional[str]: Args: did: The DID to look up on the ledger or in the cache """ - nym = self.did_to_nym(did) + nym = strip_did_prefix(did) public_info = await self.get_wallet_public_did() public_did = public_info.did if public_info else None @@ -653,7 +660,7 @@ async def get_all_endpoints_for_did(self, did: str) -> dict: Args: did: The DID to look up on the ledger or in the cache """ - nym = self.did_to_nym(did) + nym = strip_did_prefix(did) public_info = await self.get_wallet_public_did() public_did = public_info.did if public_info else None try: @@ -685,7 +692,7 @@ async def get_endpoint_for_did( if not endpoint_type: endpoint_type = EndpointType.ENDPOINT - nym = self.did_to_nym(did) + nym = strip_did_prefix(did) public_info = await self.get_wallet_public_did() public_did = public_info.did if public_info else None try: @@ -749,7 +756,7 @@ async def update_endpoint_for_did( "Error cannot update endpoint when ledger is in read only mode" ) - nym = self.did_to_nym(did) + nym = strip_did_prefix(did) attr_json = await self._construct_attr_json( endpoint, endpoint_type, all_exist_endpoints, routing_keys @@ -853,7 +860,7 @@ def nym_to_did(self, nym: str) -> str: """Format a nym with the ledger's DID prefix.""" if nym: # remove any existing prefix - nym = self.did_to_nym(nym) + nym = strip_did_prefix(nym) return f"did:sov:{nym}" async def build_and_return_get_nym_request( @@ -887,7 +894,7 @@ async def rotate_public_did_keypair(self, next_seed: Optional[str] = None) -> No await txn.commit() # fetch current nym info from ledger - nym = self.did_to_nym(public_did) + nym = strip_did_prefix(public_did) try: get_nym_req = ledger.build_get_nym_request(public_did, nym) except VdrError as err: diff --git a/acapy_agent/messaging/valid.py b/acapy_agent/messaging/valid.py index d2b99cfc92..11f110a5d9 100644 --- a/acapy_agent/messaging/valid.py +++ b/acapy_agent/messaging/valid.py @@ -350,8 +350,8 @@ def __init__(self): class IndyDID(Regexp): """Validate value against indy DID.""" - EXAMPLE = "WgWxqztrNooG92RXvxSTWv" - PATTERN = re.compile(rf"^(did:sov:)?[{B58}]{{21,22}}$") + EXAMPLE = "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw" + PATTERN = re.compile(rf"^(did:(sov|indy):)?[{B58}]{{21,22}}$") def __init__(self): """Initialize the instance.""" diff --git a/acapy_agent/revocation/indy.py b/acapy_agent/revocation/indy.py index 7c1efe6e25..14fc941c9d 100644 --- a/acapy_agent/revocation/indy.py +++ b/acapy_agent/revocation/indy.py @@ -18,6 +18,8 @@ is_author_role, ) from ..storage.base import StorageNotFoundError +from ..wallet.askar import CATEGORY_DID +from ..wallet.error import WalletNotFoundError from .error import ( RevocationError, RevocationInvalidStateValueError, @@ -79,11 +81,20 @@ async def init_issuer_registry( record_id = str(uuid4()) issuer_did = cred_def_id.split(":")[0] + # Try and get a did:indy did from nym value stored as a did + async with self._profile.session() as session: + try: + indy_did = await session.handle.fetch( + CATEGORY_DID, f"did:indy:{issuer_did}" + ) + except WalletNotFoundError: + indy_did = None + record = IssuerRevRegRecord( new_with_id=True, record_id=record_id, cred_def_id=cred_def_id, - issuer_did=issuer_did, + issuer_did=indy_did.name if indy_did else issuer_did, max_cred_num=max_cred_num, revoc_def_type=revoc_def_type, tag=tag, diff --git a/acapy_agent/revocation/tests/test_indy.py b/acapy_agent/revocation/tests/test_indy.py index 224369b372..8925d90699 100644 --- a/acapy_agent/revocation/tests/test_indy.py +++ b/acapy_agent/revocation/tests/test_indy.py @@ -95,6 +95,7 @@ async def test_init_issuer_registry_bad_size(self): async def test_get_active_issuer_rev_reg_record(self): CRED_DEF_ID = f"{self.test_did}:3:CL:1234:default" + self.profile.context.injector.bind_instance(BaseLedger, self.ledger) rec = await self.revoc.init_issuer_registry(CRED_DEF_ID) rec.revoc_reg_id = "dummy" rec.state = IssuerRevRegRecord.STATE_ACTIVE @@ -150,7 +151,7 @@ async def test_decommission_issuer_registries(self): CRED_DEF_ID = [f"{self.test_did}:3:CL:{i}:default" for i in (4321, 8765)] for cd_id in CRED_DEF_ID: - rec = await self.revoc.init_issuer_registry(cd_id) + await self.revoc.init_issuer_registry(cd_id) # 2 registries, both in init state (no listener to push into active) recs = await self.revoc.list_issuer_registries() diff --git a/acapy_agent/utils/general.py b/acapy_agent/utils/general.py index 7c01793a07..043694dada 100644 --- a/acapy_agent/utils/general.py +++ b/acapy_agent/utils/general.py @@ -1,5 +1,6 @@ """Utility functions for the admin server.""" +import re from hmac import compare_digest @@ -8,3 +9,9 @@ def const_compare(string1, string2): if string1 is None or string2 is None: return False return compare_digest(string1.encode(), string2.encode()) + + +def strip_did_prefix(did: str) -> str | None: + """Strip the DID prefix from a DID.""" + if did: + return re.sub(r"^did:\w+:", "", did) diff --git a/acapy_agent/wallet/askar.py b/acapy_agent/wallet/askar.py index 4be4ce29e4..4acf381d72 100644 --- a/acapy_agent/wallet/askar.py +++ b/acapy_agent/wallet/askar.py @@ -17,7 +17,7 @@ from .base import BaseWallet, DIDInfo, KeyInfo from .crypto import sign_message, validate_seed, verify_signed_message from .did_info import INVITATION_REUSE_KEY -from .did_method import SOV, DIDMethod, DIDMethods +from .did_method import INDY, SOV, DIDMethod, DIDMethods from .did_parameters_validation import DIDParametersValidation from .error import WalletDuplicateError, WalletError, WalletNotFoundError from .key_type import BLS12381G2, ED25519, P256, X25519, KeyType, KeyTypes @@ -451,7 +451,7 @@ async def replace_local_did_metadata(self, did: str, metadata: dict): except AskarError as err: raise WalletError("Error updating DID metadata") from err - async def get_public_did(self) -> DIDInfo: + async def get_public_did(self) -> DIDInfo | None: """Retrieve the public DID. Returns: @@ -586,8 +586,10 @@ async def set_did_endpoint( """ did_info = await self.get_local_did(did) - if did_info.method != SOV: - raise WalletError("Setting DID endpoint is only allowed for did:sov DIDs") + if did_info.method not in (SOV, INDY): + raise WalletError( + "Setting DID endpoint is only allowed for did:sov or did:indy DIDs" + ) metadata = {**did_info.metadata} if not endpoint_type: endpoint_type = EndpointType.ENDPOINT diff --git a/acapy_agent/wallet/base.py b/acapy_agent/wallet/base.py index 2f883fd2ea..c92ecf6bd1 100644 --- a/acapy_agent/wallet/base.py +++ b/acapy_agent/wallet/base.py @@ -214,7 +214,7 @@ async def create_public_did( return await self.set_public_did(did_info) @abstractmethod - async def get_public_did(self) -> DIDInfo: + async def get_public_did(self) -> DIDInfo | None: """Retrieve the public DID. Returns: diff --git a/acapy_agent/wallet/crypto.py b/acapy_agent/wallet/crypto.py index 0ceef63a91..28bf73d1f7 100644 --- a/acapy_agent/wallet/crypto.py +++ b/acapy_agent/wallet/crypto.py @@ -1,5 +1,6 @@ """Cryptography functions used by BasicWallet.""" +import hashlib import re from collections import OrderedDict from typing import Callable, List, Optional, Sequence, Tuple, Union @@ -16,6 +17,7 @@ sign_messages_bls12381g2, verify_signed_messages_bls12381g2, ) +from .did_method import INDY, SOV, DIDMethod from .error import WalletError from .key_type import BLS12381G2, ED25519, KeyType from .util import b58_to_bytes, b64_to_bytes, bytes_to_b58, random_seed @@ -63,11 +65,12 @@ def create_ed25519_keypair(seed: Optional[bytes] = None) -> Tuple[bytes, bytes]: return pk, sk -def seed_to_did(seed: str) -> str: +def seed_to_did(seed: str, method: Optional[DIDMethod] = SOV) -> str: """Derive a DID from a seed value. Args: seed: The seed to derive + method: The DID method to use Returns: The DID derived from the seed @@ -75,8 +78,14 @@ def seed_to_did(seed: str) -> str: """ seed = validate_seed(seed) verkey, _ = create_ed25519_keypair(seed) - did = bytes_to_b58(verkey[:16]) - return did + if method == SOV: + return bytes_to_b58(verkey[:16]) + if method == INDY: + # Hash the verkey, take the first 16 bytes, and convert to a base58 string + hashed_verkey = hashlib.sha256(verkey).digest() + did = bytes_to_b58(hashed_verkey[:16]) + return f"did:indy:{did}" + raise WalletError(f"Unsupported DID method: {method.method_name}") def did_is_self_certified(did: str, verkey: str) -> bool: diff --git a/acapy_agent/wallet/did_method.py b/acapy_agent/wallet/did_method.py index 3123349945..e4fe2ae3bf 100644 --- a/acapy_agent/wallet/did_method.py +++ b/acapy_agent/wallet/did_method.py @@ -65,6 +65,12 @@ def holder_defined_did(self) -> HolderDefinedDid: rotation=True, holder_defined_did=HolderDefinedDid.ALLOWED, ) +INDY = DIDMethod( + name="indy", + key_types=[ED25519], + rotation=True, + holder_defined_did=HolderDefinedDid.ALLOWED, +) KEY = DIDMethod( name="key", key_types=[ED25519, P256, BLS12381G2], @@ -105,6 +111,7 @@ def __init__(self) -> None: """Construct did method registry.""" self._registry: Dict[str, DIDMethod] = { SOV.method_name: SOV, + INDY.method_name: INDY, KEY.method_name: KEY, WEB.method_name: WEB, PEER2.method_name: PEER2, diff --git a/acapy_agent/wallet/did_parameters_validation.py b/acapy_agent/wallet/did_parameters_validation.py index baf492a080..5eb28ebf76 100644 --- a/acapy_agent/wallet/did_parameters_validation.py +++ b/acapy_agent/wallet/did_parameters_validation.py @@ -1,9 +1,11 @@ """Tooling to validate DID creation parameters.""" +import hashlib from typing import Optional from acapy_agent.did.did_key import DIDKey from acapy_agent.wallet.did_method import ( + INDY, KEY, SOV, DIDMethod, @@ -60,5 +62,7 @@ def validate_or_derive_did( return DIDKey.from_public_key(verkey, key_type).did elif method == SOV: return bytes_to_b58(verkey[:16]) if not did else did + elif method == INDY: + return bytes_to_b58(hashlib.sha256(verkey).digest()[:16]) if not did else did return did diff --git a/acapy_agent/wallet/routes.py b/acapy_agent/wallet/routes.py index 8009e13d30..9da8e70ba2 100644 --- a/acapy_agent/wallet/routes.py +++ b/acapy_agent/wallet/routes.py @@ -71,6 +71,7 @@ from .base import BaseWallet from .did_info import DIDInfo from .did_method import ( + INDY, KEY, PEER2, PEER4, @@ -588,6 +589,12 @@ async def wallet_create_did(request: web.BaseRequest): reason=f"method {body.get('method')} is not supported by the agent." ) + # Don't support Indy DID method from this endpoint + if method.method_name == INDY.method_name: + raise web.HTTPBadRequest( + reason="Indy did method is supported from /did/indy/create endpoint." + ) + key_types = session.inject(KeyTypes) # set default method and key type for backwards compat key_type = ( diff --git a/acapy_agent/wallet/tests/test_askar.py b/acapy_agent/wallet/tests/test_askar.py new file mode 100644 index 0000000000..5d6291d26c --- /dev/null +++ b/acapy_agent/wallet/tests/test_askar.py @@ -0,0 +1,51 @@ +from unittest import IsolatedAsyncioTestCase + +from acapy_agent.ledger.base import BaseLedger +from acapy_agent.tests import mock +from acapy_agent.wallet.askar import AskarWallet +from acapy_agent.wallet.did_info import DIDInfo +from acapy_agent.wallet.did_method import INDY, SOV, WEB +from acapy_agent.wallet.error import WalletError +from acapy_agent.wallet.key_type import ED25519 + +from ...utils.testing import create_test_profile + + +class TestAskar(IsolatedAsyncioTestCase): + async def asyncSetUp(self) -> None: + self.profile = await create_test_profile() + + async def test_set_did_endpoint(self): + wallet = AskarWallet(self.profile.session) + wallet.replace_local_did_metadata = mock.CoroutineMock() + + # Set endpoint for a Sov DID + sov_did_info = DIDInfo("example123", "verkey", {}, SOV, ED25519.key_type) + wallet.get_local_did = mock.CoroutineMock(return_value=sov_did_info) + wallet.get_public_did = mock.CoroutineMock(return_value=sov_did_info) + await wallet.set_did_endpoint( + "did:example:123", + "http://example.com", + mock.MagicMock(BaseLedger, autospec=True), + ) + + # Set endpoint for an Indy DID + indy_did_info = DIDInfo("did:indy:example", "verkey", {}, INDY, ED25519.key_type) + wallet.get_local_did = mock.CoroutineMock(return_value=indy_did_info) + wallet.get_public_did = mock.CoroutineMock(return_value=indy_did_info) + await wallet.set_did_endpoint( + "did:example:123", + "http://example.com", + mock.MagicMock(BaseLedger, autospec=True), + ) + + # Set endpoint for a Web DID should fail + web_did_info = DIDInfo("did:web:example:123", "verkey", {}, WEB, ED25519.key_type) + wallet.get_local_did = mock.CoroutineMock(return_value=web_did_info) + wallet.get_public_did = mock.CoroutineMock(return_value=web_did_info) + with self.assertRaises(WalletError): + await wallet.set_did_endpoint( + "did:example:123", + "http://example.com", + mock.MagicMock(BaseLedger, autospec=True), + ) diff --git a/acapy_agent/wallet/tests/test_routes.py b/acapy_agent/wallet/tests/test_routes.py index e7f9a8af1b..46e8c15f80 100644 --- a/acapy_agent/wallet/tests/test_routes.py +++ b/acapy_agent/wallet/tests/test_routes.py @@ -167,6 +167,13 @@ async def test_create_did_unsupported_key_type(self): with self.assertRaises(test_module.web.HTTPForbidden): await test_module.wallet_create_did(self.request) + async def test_create_did_indy(self): + self.request.json = mock.CoroutineMock( + return_value={"method": "indy", "options": {"key_type": ED25519.key_type}} + ) + with self.assertRaises(test_module.web.HTTPBadRequest): + await test_module.wallet_create_did(self.request) + async def test_create_did_method_requires_user_defined_did(self): # given did_custom = DIDMethod( diff --git a/scenarios/examples/did_indy_issuance_and_revocation/docker-compose.yml b/scenarios/examples/did_indy_issuance_and_revocation/docker-compose.yml new file mode 100644 index 0000000000..67e4424893 --- /dev/null +++ b/scenarios/examples/did_indy_issuance_and_revocation/docker-compose.yml @@ -0,0 +1,89 @@ + services: + alice: + image: acapy-test + ports: + - "3001:3001" + command: > + start + --label Alice + --inbound-transport http 0.0.0.0 3000 + --outbound-transport http + --endpoint http://alice:3000 + --admin 0.0.0.0 3001 + --admin-insecure-mode + --tails-server-base-url http://tails:6543 + --genesis-url http://test.bcovrin.vonx.io/genesis + --wallet-type askar + --wallet-name alice + --wallet-key insecure + --auto-provision + --log-level info + --debug-webhooks + --notify-revocation + healthcheck: + test: curl -s -o /dev/null -w '%{http_code}' "http://localhost:3001/status/live" | grep "200" > /dev/null + start_period: 30s + interval: 7s + timeout: 5s + retries: 5 + depends_on: + tails: + condition: service_started + + bob: + image: acapy-test + ports: + - "3002:3001" + command: > + start + --label Bob + --inbound-transport http 0.0.0.0 3000 + --outbound-transport http + --endpoint http://bob:3000 + --admin 0.0.0.0 3001 + --admin-insecure-mode + --tails-server-base-url http://tails:6543 + --genesis-url http://test.bcovrin.vonx.io/genesis + --wallet-type askar + --wallet-name bob + --wallet-key insecure + --auto-provision + --log-level info + --debug-webhooks + --monitor-revocation-notification + healthcheck: + test: curl -s -o /dev/null -w '%{http_code}' "http://localhost:3001/status/live" | grep "200" > /dev/null + start_period: 30s + interval: 7s + timeout: 5s + retries: 5 + + example: + container_name: controller + build: + context: ../.. + environment: + - ALICE=http://alice:3001 + - BOB=http://bob:3001 + volumes: + - ./example.py:/usr/src/app/example.py:ro,z + command: python -m example + depends_on: + alice: + condition: service_healthy + bob: + condition: service_healthy + + tails: + image: ghcr.io/bcgov/tails-server:latest + ports: + - 6543:6543 + environment: + - GENESIS_URL=http://test.bcovrin.vonx.io/genesis + command: > + tails-server + --host 0.0.0.0 + --port 6543 + --storage-path /tmp/tails-files + --log-level INFO + diff --git a/scenarios/examples/did_indy_issuance_and_revocation/example.py b/scenarios/examples/did_indy_issuance_and_revocation/example.py new file mode 100644 index 0000000000..407de5e2a5 --- /dev/null +++ b/scenarios/examples/did_indy_issuance_and_revocation/example.py @@ -0,0 +1,122 @@ +"""Minimal reproducible example script. + +This script is for you to use to reproduce a bug or demonstrate a feature. +""" + +import asyncio +import json +from dataclasses import dataclass +from os import getenv + +from acapy_controller import Controller +from acapy_controller.logging import logging_to_stdout +from acapy_controller.models import V20PresExRecord +from acapy_controller.protocols import ( + DIDResult, + didexchange, + indy_anoncred_credential_artifacts, + indy_anoncreds_publish_revocation, + indy_anoncreds_revoke, + indy_issue_credential_v2, + indy_present_proof_v2, + params, +) +from aiohttp import ClientSession + +ALICE = getenv("ALICE", "http://alice:3001") +BOB = getenv("BOB", "http://bob:3001") + + +def summary(presentation: V20PresExRecord) -> str: + """Summarize a presentation exchange record.""" + request = presentation.pres_request + return "Summary: " + json.dumps( + { + "state": presentation.state, + "verified": presentation.verified, + "presentation_request": request.dict(by_alias=True) if request else None, + }, + indent=2, + sort_keys=True, + ) + + +@dataclass +class IndyDidCreateResponse: + """Response from creating a DID.""" + + did: str + verkey: str + + +async def main(): + """Test Controller protocols.""" + async with Controller(base_url=ALICE) as alice, Controller(base_url=BOB) as bob: + # Connecting + alice_conn, bob_conn = await didexchange(alice, bob) + + # Issuance prep + config = (await alice.get("/status/config"))["config"] + genesis_url = config.get("ledger.genesis_url") + public_did = (await alice.get("/wallet/did/public", response=DIDResult)).result + if not public_did: + public_did = await alice.post( + "/did/indy/create", + json={}, + response=IndyDidCreateResponse, + ) + assert public_did + + async with ClientSession() as session: + register_url = genesis_url.replace("/genesis", "/register") + async with session.post( + register_url, + json={ + "did": public_did.did, + "verkey": public_did.verkey, + "alias": None, + "role": "ENDORSER", + }, + ) as resp: + assert resp.ok + + await alice.post("/wallet/did/public", params=params(did=public_did.did)) + _, cred_def = await indy_anoncred_credential_artifacts( + alice, + ["firstname", "lastname"], + support_revocation=True, + ) + + # Issue a credential + alice_cred_ex, _ = await indy_issue_credential_v2( + alice, + bob, + alice_conn.connection_id, + bob_conn.connection_id, + cred_def.credential_definition_id, + {"firstname": "Bob", "lastname": "Builder"}, + ) + + # Present the the credential's attributes + await indy_present_proof_v2( + bob, + alice, + bob_conn.connection_id, + alice_conn.connection_id, + requested_attributes=[{"name": "firstname"}], + ) + + # Revoke credential + await indy_anoncreds_revoke( + alice, + cred_ex=alice_cred_ex, + holder_connection_id=alice_conn.connection_id, + notify=True, + ) + await indy_anoncreds_publish_revocation(alice, cred_ex=alice_cred_ex) + await bob.record(topic="revocation-notification") + + +if __name__ == "__main__": + logging_to_stdout() + asyncio.run(main()) From 825840b8751b704874bee8c3fa6663aae632cb92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Feb 2025 10:00:48 -0800 Subject: [PATCH 13/76] chore(deps): Bump prompt-toolkit from 2.0.10 to 3.0.50 (#3526) * chore(deps): Bump prompt-toolkit from 2.0.10 to 3.0.50 Bumps [prompt-toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) from 2.0.10 to 3.0.50. - [Release notes](https://github.com/prompt-toolkit/python-prompt-toolkit/releases) - [Changelog](https://github.com/prompt-toolkit/python-prompt-toolkit/blob/master/CHANGELOG) - [Commits](https://github.com/prompt-toolkit/python-prompt-toolkit/compare/2.0.10...3.0.50) --- updated-dependencies: - dependency-name: prompt-toolkit dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * :art: Remove `use_asyncio_event_loop` -- prompt-toolkit now runs on top of asyncio by default Signed-off-by: ff137 * :art: Remove need for prompt init Signed-off-by: ff137 * :white_check_mark: Remove mocking of unused function Signed-off-by: ff137 * :white_check_mark: Mock only `sys.stdout.isatty`, not `sys.stdout` Signed-off-by: ff137 --------- Signed-off-by: dependabot[bot] Signed-off-by: ff137 Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: ff137 Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- acapy_agent/config/ledger.py | 4 - acapy_agent/config/tests/test_ledger.py | 13 +-- demo/runners/support/utils.py | 9 -- poetry.lock | 127 ++---------------------- pyproject.toml | 2 +- 5 files changed, 13 insertions(+), 142 deletions(-) diff --git a/acapy_agent/config/ledger.py b/acapy_agent/config/ledger.py index e8a4791e38..6cda513ba6 100644 --- a/acapy_agent/config/ledger.py +++ b/acapy_agent/config/ledger.py @@ -8,7 +8,6 @@ import markdown import prompt_toolkit -from prompt_toolkit.eventloop.defaults import use_asyncio_event_loop from prompt_toolkit.formatted_text import HTML from uuid_utils import uuid4 @@ -211,9 +210,6 @@ async def select_aml_tty(taa_info, provision: bool = False) -> Optional[str]: + taa_html ) - # setup for prompt_toolkit - use_asyncio_event_loop() - prompt_toolkit.print_formatted_text(HTML(taa_html)) opts = [] diff --git a/acapy_agent/config/tests/test_ledger.py b/acapy_agent/config/tests/test_ledger.py index 813e9c5d88..3fb5af3f49 100644 --- a/acapy_agent/config/tests/test_ledger.py +++ b/acapy_agent/config/tests/test_ledger.py @@ -1,3 +1,4 @@ +import sys from unittest import IsolatedAsyncioTestCase import pytest @@ -634,9 +635,8 @@ async def test_ledger_accept_taa_not_tty_not_accept_config(self, mock_stdout): None, self.profile, taa_info, provision=False ) - @mock.patch("sys.stdout") - async def test_ledger_accept_taa_tty(self, mock_stdout): - mock_stdout.isatty = mock.MagicMock(return_value=True) + async def test_ledger_accept_taa_tty(self): + sys.stdout.isatty = mock.MagicMock(return_value=True) self.profile = await create_test_profile() taa_info = { @@ -645,7 +645,6 @@ async def test_ledger_accept_taa_tty(self, mock_stdout): } with ( - mock.patch.object(test_module, "use_asyncio_event_loop", mock.MagicMock()), mock.patch.object( test_module.prompt_toolkit, "prompt", mock.CoroutineMock() ) as mock_prompt, @@ -656,9 +655,6 @@ async def test_ledger_accept_taa_tty(self, mock_stdout): ) with ( - mock.patch.object( - test_module, "use_asyncio_event_loop", mock.MagicMock() - ) as mock_use_aio_loop, mock.patch.object( test_module.prompt_toolkit, "prompt", mock.CoroutineMock() ) as mock_prompt, @@ -669,9 +665,6 @@ async def test_ledger_accept_taa_tty(self, mock_stdout): ) with ( - mock.patch.object( - test_module, "use_asyncio_event_loop", mock.MagicMock() - ) as mock_use_aio_loop, mock.patch.object( test_module.prompt_toolkit, "prompt", mock.CoroutineMock() ) as mock_prompt, diff --git a/demo/runners/support/utils.py b/demo/runners/support/utils.py index ebd8c9e67b..609528da4c 100644 --- a/demo/runners/support/utils.py +++ b/demo/runners/support/utils.py @@ -7,7 +7,6 @@ import prompt_toolkit import pygments from prompt_toolkit.application import run_in_terminal -from prompt_toolkit.eventloop.defaults import use_asyncio_event_loop from prompt_toolkit.formatted_text import FormattedText, PygmentsTokens from prompt_toolkit.patch_stdout import patch_stdout from prompt_toolkit.shortcuts import ProgressBar @@ -142,15 +141,7 @@ def flatten(args): yield arg -def prompt_init(): - if hasattr(prompt_init, "_called"): - return - prompt_init._called = True - use_asyncio_event_loop() - - async def prompt(*args, **kwargs): - prompt_init() with patch_stdout(): try: while True: diff --git a/poetry.lock b/poetry.lock index eb8c2ecd1a..0d703ce45d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -6,7 +6,6 @@ version = "2.4.4" description = "Happy Eyeballs for asyncio" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "aiohappyeyeballs-2.4.4-py3-none-any.whl", hash = "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8"}, {file = "aiohappyeyeballs-2.4.4.tar.gz", hash = "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745"}, @@ -18,7 +17,6 @@ version = "3.11.12" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "aiohttp-3.11.12-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:aa8a8caca81c0a3e765f19c6953416c58e2f4cc1b84829af01dd1c771bb2f91f"}, {file = "aiohttp-3.11.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84ede78acde96ca57f6cf8ccb8a13fbaf569f6011b9a52f870c662d4dc8cd854"}, @@ -121,7 +119,6 @@ version = "3.0.3" description = "Build and document REST APIs with aiohttp and apispec" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "aiohttp_apispec_acapy-3.0.3-py3-none-any.whl", hash = "sha256:9a5d335c22975da1bbde49ddc04c138ee285d7c38354e88b43babef2eec0bc54"}, {file = "aiohttp_apispec_acapy-3.0.3.tar.gz", hash = "sha256:8cec5f2601f8c2d7d53dd4aebab3975a596d86ea3a1a362eb3b1adadc11662b3"}, @@ -139,7 +136,6 @@ version = "0.7.0" description = "CORS support for aiohttp" optional = false python-versions = "*" -groups = ["main"] files = [ {file = "aiohttp-cors-0.7.0.tar.gz", hash = "sha256:4d39c6d7100fd9764ed1caf8cebf0eb01bf5e3f24e2e073fda6234bc48b19f5d"}, {file = "aiohttp_cors-0.7.0-py3-none-any.whl", hash = "sha256:0451ba59fdf6909d0e2cd21e4c0a43752bc0703d33fc78ae94d9d9321710193e"}, @@ -154,7 +150,6 @@ version = "1.3.2" description = "aiosignal: a list of registered asynchronous callbacks" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"}, {file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"}, @@ -169,7 +164,6 @@ version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, @@ -181,7 +175,6 @@ version = "0.2.0" description = "" optional = false python-versions = ">=3.6.3" -groups = ["main"] files = [ {file = "anoncreds-0.2.0-py3-none-macosx_10_9_universal2.whl", hash = "sha256:ec57e224d5f1b8749c3d6ff75bb61229a4f9c31df1ee863835f025c78ec10cd0"}, {file = "anoncreds-0.2.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:55dd0ad8c8611d2f6af158485dbd2f3c9524694ee4eaf1c5558973f1e436f943"}, @@ -195,7 +188,6 @@ version = "6.8.1" description = "A pluggable API specification generator. Currently supports the OpenAPI Specification (f.k.a. the Swagger specification)." optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "apispec-6.8.1-py3-none-any.whl", hash = "sha256:eacba00df745efc9adb2a45cf992300e87938582077e101fb26b78ecf4320beb"}, {file = "apispec-6.8.1.tar.gz", hash = "sha256:f4916cbb7be156963b18f5929a0e42bd2349135834b680a81b12432bcfaa9a39"}, @@ -217,7 +209,6 @@ version = "0.4.3" description = "" optional = false python-versions = ">=3.6.3" -groups = ["main"] files = [ {file = "aries_askar-0.4.3-py3-none-macosx_10_9_universal2.whl", hash = "sha256:fd4073f4abc7bfe423f3a637cb0d2e5fb1b96cfd0e798ee69e26eb5b9528c3e4"}, {file = "aries_askar-0.4.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:a787fdbf343efcdb9f26ce75ed934c2d48378cef08ae5ce69e997cba7c3f1992"}, @@ -231,7 +222,6 @@ version = "24.3.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"}, {file = "attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff"}, @@ -251,7 +241,6 @@ version = "2.1.1" description = "Base58 and Base58Check implementation." optional = false python-versions = ">=3.5" -groups = ["main"] files = [ {file = "base58-2.1.1-py3-none-any.whl", hash = "sha256:11a36f4d3ce51dfc1043f3218591ac4eb1ceb172919cebe05b52a5bcc8d245c2"}, {file = "base58-2.1.1.tar.gz", hash = "sha256:c5d0cb3f5b6e81e8e35da5754388ddcc6d0d14b6c6a132cb93d69ed580a7278c"}, @@ -266,7 +255,6 @@ version = "0.3.0" description = "Python library for general Base-N encodings." optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "bases-0.3.0-py3-none-any.whl", hash = "sha256:a2fef3366f3e522ff473d2e95c21523fe8e44251038d5c6150c01481585ebf5b"}, {file = "bases-0.3.0.tar.gz", hash = "sha256:70f04a4a45d63245787f9e89095ca11042685b6b64b542ad916575ba3ccd1570"}, @@ -285,7 +273,6 @@ version = "5.5.1" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "cachetools-5.5.1-py3-none-any.whl", hash = "sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb"}, {file = "cachetools-5.5.1.tar.gz", hash = "sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95"}, @@ -297,7 +284,6 @@ version = "2.0.0" description = "Canonical JSON" optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "canonicaljson-2.0.0-py3-none-any.whl", hash = "sha256:c38a315de3b5a0532f1ec1f9153cd3d716abfc565a558d00a4835428a34fca5b"}, {file = "canonicaljson-2.0.0.tar.gz", hash = "sha256:e2fdaef1d7fadc5d9cb59bd3d0d41b064ddda697809ac4325dced721d12f113f"}, @@ -309,7 +295,6 @@ version = "2024.12.14" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" -groups = ["main"] files = [ {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, @@ -321,7 +306,6 @@ version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, @@ -401,7 +385,6 @@ version = "3.4.0" description = "Validate configuration and produce human readable error messages." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, @@ -413,7 +396,6 @@ version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, @@ -515,8 +497,6 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main", "dev"] -markers = "sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -528,7 +508,6 @@ version = "1.7" description = "A drop-in replacement for argparse that allows options to also be set via config files and/or environment variables." optional = false python-versions = ">=3.5" -groups = ["main"] files = [ {file = "ConfigArgParse-1.7-py3-none-any.whl", hash = "sha256:d249da6591465c6c26df64a9f73d2536e743be2f244eb3ebe61114af2f94f86b"}, {file = "ConfigArgParse-1.7.tar.gz", hash = "sha256:e7067471884de5478c58a511e529f0f9bd1c66bfef1dea90935438d6c23306d1"}, @@ -544,7 +523,6 @@ version = "7.6.10" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "coverage-7.6.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78"}, {file = "coverage-7.6.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c"}, @@ -619,7 +597,6 @@ version = "44.0.0" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.7" -groups = ["main"] files = [ {file = "cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092"}, @@ -627,7 +604,6 @@ files = [ {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543"}, - {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:60eb32934076fa07e4316b7b2742fa52cbb190b42c2df2863dbc4230a0a9b385"}, {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e"}, {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e"}, {file = "cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053"}, @@ -638,7 +614,6 @@ files = [ {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c"}, - {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9abcc2e083cbe8dde89124a47e5e53ec38751f0d7dfd36801008f316a127d7ba"}, {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64"}, {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285"}, {file = "cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417"}, @@ -671,8 +646,6 @@ version = "1.0.1" description = "Cython implementation of Toolz: High performance functional utilities" optional = false python-versions = ">=3.8" -groups = ["main"] -markers = "implementation_name == \"cpython\"" files = [ {file = "cytoolz-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cec9af61f71fc3853eb5dca3d42eb07d1f48a4599fa502cbe92adde85f74b042"}, {file = "cytoolz-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:140bbd649dbda01e91add7642149a5987a7c3ccc251f2263de894b89f50b6608"}, @@ -788,7 +761,6 @@ version = "1.8.12" description = "An implementation of the Debug Adapter Protocol for Python" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "debugpy-1.8.12-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:a2ba7ffe58efeae5b8fad1165357edfe01464f9aef25e814e891ec690e7dd82a"}, {file = "debugpy-1.8.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbbd4149c4fc5e7d508ece083e78c17442ee13b0e69bfa6bd63003e486770f45"}, @@ -824,7 +796,6 @@ version = "2.0" description = "A toolset for deeply merging Python dictionaries." optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "deepmerge-2.0-py3-none-any.whl", hash = "sha256:6de9ce507115cff0bed95ff0ce9ecc31088ef50cbdf09bc90a09349a318b3d00"}, {file = "deepmerge-2.0.tar.gz", hash = "sha256:5c3d86081fbebd04dd5de03626a0607b809a98fb6ccba5770b62466fe940ff20"}, @@ -839,7 +810,6 @@ version = "0.1.2" description = "An implementation of did:peer:2" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "did_peer_2-0.1.2-py3-none-any.whl", hash = "sha256:d5908cda2d52b7c34428a421044507d7847fd79b78dc8360441c408f4507d612"}, {file = "did_peer_2-0.1.2.tar.gz", hash = "sha256:af8623f62022732e9fadc0289dfb886fd8267767251c4fa0b63694ecd29a7086"}, @@ -854,7 +824,6 @@ version = "0.1.4" description = "An implementation of did:peer:4" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "did_peer_4-0.1.4-py3-none-any.whl", hash = "sha256:4c2bb42a55e4fec08fe008a1585db2f11fe19e36121f8919991add027d7c816f"}, {file = "did_peer_4-0.1.4.tar.gz", hash = "sha256:b367922067b428d33458ca36158eaed40c863cde2fbab6a18a523dccad533c8e"}, @@ -869,7 +838,6 @@ version = "0.3.0" description = "This repository includes Python libraries for working with `did:webvh` (did:web + Verified History) DID documents and the underlying log format." optional = false python-versions = ">= 3.10, <4" -groups = ["main"] files = [] develop = false @@ -892,8 +860,6 @@ version = "0.1.1" description = "DIDComm Messaging implemented with swappable backends." optional = true python-versions = ">=3.9" -groups = ["main"] -markers = "extra == \"didcommv2\"" files = [ {file = "didcomm_messaging-0.1.1-py3-none-any.whl", hash = "sha256:5350006d3a92e085dd208add738d6439c2b0a950c1fe19011ece71de0574cc1a"}, {file = "didcomm_messaging-0.1.1.tar.gz", hash = "sha256:e3c7c7612b8f9710ccd221b2f5e8456cbf868600f7cc10474fcc98be325702eb"}, @@ -915,7 +881,6 @@ version = "0.3.9" description = "Distribution utilities" optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, @@ -927,7 +892,6 @@ version = "0.19.0" description = "ECDSA cryptographic signature library (pure python)" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.6" -groups = ["main"] files = [ {file = "ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a"}, {file = "ecdsa-0.19.0.tar.gz", hash = "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8"}, @@ -946,7 +910,6 @@ version = "0.7.1" description = "eth-hash: The Ethereum hashing function, keccak256, sometimes (erroneously) called sha3" optional = false python-versions = "<4,>=3.8" -groups = ["main"] files = [ {file = "eth_hash-0.7.1-py3-none-any.whl", hash = "sha256:0fb1add2adf99ef28883fd6228eb447ef519ea72933535ad1a0b28c6f65f868a"}, {file = "eth_hash-0.7.1.tar.gz", hash = "sha256:d2411a403a0b0a62e8247b4117932d900ffb4c8c64b15f92620547ca5ce46be5"}, @@ -965,7 +928,6 @@ version = "5.1.0" description = "eth-typing: Common type annotations for ethereum python packages" optional = false python-versions = "<4,>=3.8" -groups = ["main"] files = [ {file = "eth_typing-5.1.0-py3-none-any.whl", hash = "sha256:c0d6b93f5385aa84efc4b47ae2bd478da069bc0ffda8b67e0ccb573f43defd29"}, {file = "eth_typing-5.1.0.tar.gz", hash = "sha256:8581f212ee6252aaa285377a77620f6e5f6e16ac3f144c61f098fafd47967b1a"}, @@ -985,7 +947,6 @@ version = "5.2.0" description = "eth-utils: Common utility functions for python code that interacts with Ethereum" optional = false python-versions = "<4,>=3.8" -groups = ["main"] files = [ {file = "eth_utils-5.2.0-py3-none-any.whl", hash = "sha256:4d43eeb6720e89a042ad5b28d4b2111630ae764f444b85cbafb708d7f076da10"}, {file = "eth_utils-5.2.0.tar.gz", hash = "sha256:17e474eb654df6e18f20797b22c6caabb77415a996b3ba0f3cc8df3437463134"}, @@ -1008,7 +969,6 @@ version = "2.1.1" description = "execnet: rapid multi-Python deployment" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"}, {file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"}, @@ -1023,7 +983,6 @@ version = "3.17.0" description = "A platform independent file lock." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "filelock-3.17.0-py3-none-any.whl", hash = "sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338"}, {file = "filelock-3.17.0.tar.gz", hash = "sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e"}, @@ -1040,7 +999,6 @@ version = "2.4.6" description = "A simple immutable dictionary" optional = false python-versions = ">=3.6" -groups = ["main"] files = [ {file = "frozendict-2.4.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c3a05c0a50cab96b4bb0ea25aa752efbfceed5ccb24c007612bc63e51299336f"}, {file = "frozendict-2.4.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f5b94d5b07c00986f9e37a38dd83c13f5fe3bf3f1ccc8e88edea8fe15d6cd88c"}, @@ -1089,7 +1047,6 @@ version = "1.5.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, @@ -1191,7 +1148,6 @@ version = "2.6.6" description = "File identification library for Python" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "identify-2.6.6-py2.py3-none-any.whl", hash = "sha256:cbd1810bce79f8b671ecb20f53ee0ae8e86ae84b557de31d89709dc2a48ba881"}, {file = "identify-2.6.6.tar.gz", hash = "sha256:7bec12768ed44ea4761efb47806f0a41f86e7c0a5fdf5950d4648c90eca7e251"}, @@ -1206,7 +1162,6 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" -groups = ["main"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -1221,7 +1176,6 @@ version = "1.1.1" description = "" optional = false python-versions = ">=3.6.3" -groups = ["main"] files = [ {file = "indy_credx-1.1.1-py3-none-macosx_10_9_universal2.whl", hash = "sha256:522b90a2362de681e8224b7e5173a9a6093dc48b2ed13599c9eca3df36e29128"}, {file = "indy_credx-1.1.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:05f9a96166f79799c39c62723d78c5480fe9a872dd9dee9fbff1f79d0484c893"}, @@ -1235,7 +1189,6 @@ version = "0.4.2" description = "" optional = false python-versions = ">=3.6.3" -groups = ["main"] files = [ {file = "indy_vdr-0.4.2-py3-none-macosx_10_9_universal2.whl", hash = "sha256:21e4cc22bdb1de581e4abe00e2201d970f46e05d2420437fe023052614867553"}, {file = "indy_vdr-0.4.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:9dc8e16e8a0c4666c1a9f0a3e9967cb3dace92975b8dbb9b0aa2c7785ac5e12b"}, @@ -1249,7 +1202,6 @@ version = "0.5.1" description = "A port of Ruby on Rails inflector to Python" optional = false python-versions = ">=3.5" -groups = ["main"] files = [ {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"}, {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"}, @@ -1261,7 +1213,6 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -1273,7 +1224,6 @@ version = "3.1.5" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, @@ -1291,7 +1241,6 @@ version = "0.2.3" description = "Typed Python implementation of JSON Canonicalization Scheme as described in RFC 8785. Currently lacks full floating point support" optional = false python-versions = ">=3.8,<4.0" -groups = ["main"] files = [ {file = "jsoncanon-0.2.3-py3-none-any.whl", hash = "sha256:adb35dac2d0c5dd56f1cb374f1ea6f1fff2ebbb4e844b06d9c96b9ccadf12bf0"}, {file = "jsoncanon-0.2.3.tar.gz", hash = "sha256:483c1ef14e6c8151ba69c0bf646551f249698dd523e9c6da1339a688c5f96d6d"}, @@ -1303,9 +1252,10 @@ version = "1.7.0" description = "A final implementation of JSONPath for Python that aims to be standard compliant, including arithmetic and binary comparison operators and providing clear AST for metaprogramming." optional = false python-versions = "*" -groups = ["main"] files = [ {file = "jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c"}, + {file = "jsonpath_ng-1.7.0-py2-none-any.whl", hash = "sha256:898c93fc173f0c336784a3fa63d7434297544b7198124a68f9a3ef9597b0ae6e"}, + {file = "jsonpath_ng-1.7.0-py3-none-any.whl", hash = "sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6"}, ] [package.dependencies] @@ -1317,7 +1267,6 @@ version = "1.5.6" description = "Implementation of JOSE Web standards" optional = false python-versions = ">= 3.8" -groups = ["main"] files = [ {file = "jwcrypto-1.5.6-py3-none-any.whl", hash = "sha256:150d2b0ebbdb8f40b77f543fb44ffd2baeff48788be71f67f03566692fd55789"}, {file = "jwcrypto-1.5.6.tar.gz", hash = "sha256:771a87762a0c081ae6166958a954f80848820b2ab066937dc8b8379d65b1b039"}, @@ -1333,7 +1282,6 @@ version = "5.3.0" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=3.6" -groups = ["main"] files = [ {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"}, {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"}, @@ -1488,7 +1436,6 @@ version = "3.7" description = "Python implementation of John Gruber's Markdown." optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"}, {file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"}, @@ -1504,7 +1451,6 @@ version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, @@ -1575,7 +1521,6 @@ version = "3.26.1" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "marshmallow-3.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c"}, {file = "marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6"}, @@ -1595,7 +1540,6 @@ version = "6.1.0" description = "multidict implementation" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, @@ -1697,7 +1641,6 @@ version = "0.3.1.post4" description = "Python implementation of multiformats protocols." optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "multiformats-0.3.1.post4-py3-none-any.whl", hash = "sha256:5b1d61bd8275c9e817bdbee38dbd501b26629011962ee3c86c46e7ccd0b14129"}, {file = "multiformats-0.3.1.post4.tar.gz", hash = "sha256:d00074fdbc7d603c2084b4c38fa17bbc28173cf2750f51f46fbbc5c4d5605fbb"}, @@ -1719,7 +1662,6 @@ version = "0.3.1" description = "Pre-loading configuration module for the 'multiformats' package." optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "multiformats-config-0.3.1.tar.gz", hash = "sha256:7eaa80ef5d9c5ee9b86612d21f93a087c4a655cbcb68960457e61adbc62b47a7"}, {file = "multiformats_config-0.3.1-py3-none-any.whl", hash = "sha256:dec4c9d42ed0d9305889b67440f72e8e8d74b82b80abd7219667764b5b0a8e1d"}, @@ -1737,7 +1679,6 @@ version = "1.6.0" description = "Patch asyncio to allow nested event loops" optional = false python-versions = ">=3.5" -groups = ["main"] files = [ {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, @@ -1749,7 +1690,6 @@ version = "1.9.1" description = "Node.js virtual environment builder" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["dev"] files = [ {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, @@ -1761,7 +1701,6 @@ version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, @@ -1773,7 +1712,6 @@ version = "11.1.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "pillow-11.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:e1abe69aca89514737465752b4bcaf8016de61b3be1397a8fc260ba33321b3a8"}, {file = "pillow-11.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c640e5a06869c75994624551f45e5506e4256562ead981cce820d5ab39ae2192"}, @@ -1862,7 +1800,6 @@ version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, @@ -1879,7 +1816,6 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -1895,7 +1831,6 @@ version = "3.11" description = "Python Lex & Yacc" optional = false python-versions = "*" -groups = ["main"] files = [ {file = "ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"}, {file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"}, @@ -1907,7 +1842,6 @@ version = "3.1.1" description = "Wraps the portalocker recipe for easy usage" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "portalocker-3.1.1-py3-none-any.whl", hash = "sha256:80e984e24de292ff258a5bea0e4f3f778fff84c0ae1275dbaebc4658de4aacb3"}, {file = "portalocker-3.1.1.tar.gz", hash = "sha256:ec20f6dda2ad9ce89fa399a5f31f4f1495f515958f0cb7ca6543cef7bb5a749e"}, @@ -1927,7 +1861,6 @@ version = "4.1.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b"}, {file = "pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4"}, @@ -1942,19 +1875,16 @@ virtualenv = ">=20.10.0" [[package]] name = "prompt-toolkit" -version = "2.0.10" +version = "3.0.50" description = "Library for building powerful interactive command lines in Python" optional = false -python-versions = ">=2.6,<3.0.dev0 || >=3.3.dev0" -groups = ["main"] +python-versions = ">=3.8.0" files = [ - {file = "prompt_toolkit-2.0.10-py2-none-any.whl", hash = "sha256:e7f8af9e3d70f514373bf41aa51bc33af12a6db3f71461ea47fea985defb2c31"}, - {file = "prompt_toolkit-2.0.10-py3-none-any.whl", hash = "sha256:46642344ce457641f28fc9d1c9ca939b63dadf8df128b86f1b9860e59c73a5e4"}, - {file = "prompt_toolkit-2.0.10.tar.gz", hash = "sha256:f15af68f66e664eaa559d4ac8a928111eebd5feda0c11738b5998045224829db"}, + {file = "prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198"}, + {file = "prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab"}, ] [package.dependencies] -six = ">=1.9.0" wcwidth = "*" [[package]] @@ -1963,7 +1893,6 @@ version = "0.2.1" description = "Accelerated property cache" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6"}, {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2"}, @@ -2055,7 +1984,6 @@ version = "2.22" description = "C parser in Python" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -2067,7 +1995,6 @@ version = "2.10.5" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"}, {file = "pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff"}, @@ -2088,7 +2015,6 @@ version = "2.27.2" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, @@ -2201,7 +2127,6 @@ version = "3.3.0" description = "PyDev.Debugger (used in PyDev, PyCharm and VSCode Python)" optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "pydevd-3.3.0-cp310-cp310-macosx_14_0_universal2.whl", hash = "sha256:5a3a6948d09db219754efdd254fb462aa68a76e635cabc9cb7e95669ce161b14"}, {file = "pydevd-3.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:04fad1696d596e7bc0e938ca6a08bc0abcc9f6e10099b67148c9fe8abdddf36a"}, @@ -2248,7 +2173,6 @@ version = "251.18673.39" description = "PyCharm Debugger (used in PyCharm and PyDev)" optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "pydevd_pycharm-251.18673.39.tar.gz", hash = "sha256:52c3abb328050d6d367688d0999a8cce1d9bca59cddc0a237f955a14907bd68d"}, ] @@ -2259,7 +2183,6 @@ version = "0.5.1" description = "Python library for validating, constructing, and representing DIDs and DID Documents" optional = false python-versions = "<4.0.0,>=3.9.0" -groups = ["main"] files = [ {file = "pydid-0.5.1-py3-none-any.whl", hash = "sha256:be89df79b6267ec1814d49cdd240262c8bbddbfcee9e3aad97a97d521620d6c4"}, {file = "pydid-0.5.1.tar.gz", hash = "sha256:9489a5fbfbecc8dc864c461bb5a0c664895726ab3ca83daf389d91a10146d5e2"}, @@ -2276,7 +2199,6 @@ version = "2.10.1" description = "JSON Web Token implementation in Python" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, @@ -2294,7 +2216,6 @@ version = "2.0.4" description = "Python implementation of the JSON-LD API" optional = false python-versions = "*" -groups = ["main"] files = [ {file = "PyLD-2.0.4-py3-none-any.whl", hash = "sha256:6dab9905644616df33f8755489fc9b354ed7d832d387b7d1974b4fbd3b8d2a89"}, {file = "PyLD-2.0.4.tar.gz", hash = "sha256:311e350f0dbc964311c79c28e86f84e195a81d06fef5a6f6ac2a4f6391ceeacc"}, @@ -2317,7 +2238,6 @@ version = "1.5.0" description = "Python binding to the Networking and Cryptography (NaCl) library" optional = false python-versions = ">=3.6" -groups = ["main"] files = [ {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, @@ -2344,7 +2264,6 @@ version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, @@ -2365,7 +2284,6 @@ version = "0.25.3" description = "Pytest support for asyncio" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "pytest_asyncio-0.25.3-py3-none-any.whl", hash = "sha256:9e89518e0f9bd08928f97a3482fdc4e244df17529460bc038291ccaf8f85c7c3"}, {file = "pytest_asyncio-0.25.3.tar.gz", hash = "sha256:fc1da2cf9f125ada7e710b4ddad05518d4cee187ae9412e9ac9271003497f07a"}, @@ -2384,7 +2302,6 @@ version = "6.0.0" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"}, {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"}, @@ -2403,7 +2320,6 @@ version = "0.4.1" description = "pytest plugin to check ruff requirements." optional = false python-versions = "<4.0,>=3.8" -groups = ["dev"] files = [ {file = "pytest_ruff-0.4.1-py3-none-any.whl", hash = "sha256:69acd5b2ba68d65998c730b5b4d656788193190e45f61a53aa66ef8b390634a4"}, {file = "pytest_ruff-0.4.1.tar.gz", hash = "sha256:2c9a30f15f384c229c881b52ec86cfaf1e79d39530dd7dd5f2d6aebe278f7eb7"}, @@ -2419,7 +2335,6 @@ version = "3.6.1" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7"}, {file = "pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"}, @@ -2440,7 +2355,6 @@ version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main"] files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -2455,7 +2369,6 @@ version = "3.2.1" description = "JSON Log Formatter for the Python Logging Package" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "python_json_logger-3.2.1-py3-none-any.whl", hash = "sha256:cdc17047eb5374bd311e748b42f99d71223f3b0e186f4206cc5d52aefe85b090"}, {file = "python_json_logger-3.2.1.tar.gz", hash = "sha256:8eb0554ea17cb75b05d2848bc14fb02fbdbd9d6972120781b974380bfa162008"}, @@ -2470,8 +2383,6 @@ version = "308" description = "Python for Window Extensions" optional = false python-versions = "*" -groups = ["main"] -markers = "platform_system == \"Windows\"" files = [ {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, @@ -2499,7 +2410,6 @@ version = "6.0.2" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, @@ -2562,7 +2472,6 @@ version = "8.0" description = "QR Code image generator" optional = false python-versions = "<4.0,>=3.9" -groups = ["main"] files = [ {file = "qrcode-8.0-py3-none-any.whl", hash = "sha256:9fc05f03305ad27a709eb742cf3097fa19e6f6f93bb9e2f039c0979190f6f1b1"}, {file = "qrcode-8.0.tar.gz", hash = "sha256:025ce2b150f7fe4296d116ee9bad455a6643ab4f6e7dce541613a4758cbce347"}, @@ -2583,7 +2492,6 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -2605,7 +2513,6 @@ version = "4.1.0" description = "rlp: A package for Recursive Length Prefix encoding and decoding" optional = false python-versions = "<4,>=3.8" -groups = ["main"] files = [ {file = "rlp-4.1.0-py3-none-any.whl", hash = "sha256:8eca394c579bad34ee0b937aecb96a57052ff3716e19c7a578883e767bc5da6f"}, {file = "rlp-4.1.0.tar.gz", hash = "sha256:be07564270a96f3e225e2c107db263de96b5bc1f27722d2855bd3459a08e95a9"}, @@ -2626,7 +2533,6 @@ version = "0.9.6" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "ruff-0.9.6-py3-none-linux_armv6l.whl", hash = "sha256:2f218f356dd2d995839f1941322ff021c72a492c470f0b26a34f844c29cdf5ba"}, {file = "ruff-0.9.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b908ff4df65dad7b251c9968a2e4560836d8f5487c2f0cc238321ed951ea0504"}, @@ -2654,7 +2560,6 @@ version = "0.10.4" description = "The reference implementation of the IETF SD-JWT specification." optional = false python-versions = ">=3.8,<4.0" -groups = ["main"] files = [ {file = "sd_jwt-0.10.4-py3-none-any.whl", hash = "sha256:d7ae669eb5d51bceeb38e0df8ab2faddd12e3b21ab64d831b6d048fc1e00ce75"}, {file = "sd_jwt-0.10.4.tar.gz", hash = "sha256:82f93e2f570cfd31fab124e301febb81f3bcad70b10e38f5f9cff70ad659c2ce"}, @@ -2670,7 +2575,6 @@ version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main"] files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -2682,8 +2586,6 @@ version = "1.0.0" description = "List processing tools and functional utilities" optional = false python-versions = ">=3.8" -groups = ["main"] -markers = "implementation_name == \"cpython\" or implementation_name == \"pypy\"" files = [ {file = "toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236"}, {file = "toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02"}, @@ -2695,7 +2597,6 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -2707,7 +2608,6 @@ version = "1.2.11.post4" description = "A simple library for runtime type-checking." optional = false python-versions = ">=3.7" -groups = ["main"] files = [ {file = "typing_validation-1.2.11.post4-py3-none-any.whl", hash = "sha256:73dd504ddebf5210e80d5f65ba9b30efbd0fa42f266728fda7c4f0ba335c699c"}, {file = "typing_validation-1.2.11.post4.tar.gz", hash = "sha256:7aed04ecfbda07e63b7266f90e5d096f96344f7facfe04bb081b21e4a9781670"}, @@ -2722,7 +2622,6 @@ version = "0.2.0" description = "Unflatten dict to dict with nested dict/arrays" optional = false python-versions = "*" -groups = ["main"] files = [ {file = "unflatten-0.2.0-py2.py3-none-any.whl", hash = "sha256:a0afa7ff22313dcc60ff45110b796ed5b4e908614826e8672a9f76d3a20c1f54"}, {file = "unflatten-0.2.0.tar.gz", hash = "sha256:9710bc558882f697bc36a95a97614be296f07c8f8df1bc2b4ef96c189ce5cf84"}, @@ -2734,7 +2633,6 @@ version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, @@ -2752,8 +2650,6 @@ version = "1.0.1" description = "" optional = true python-versions = ">=3.6.3" -groups = ["main"] -markers = "extra == \"bbs\"" files = [ {file = "ursa_bbs_signatures-1.0.1-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:245701789df0d6cda09faa6194b590c0ce6513b39d80fe8f1fe2a52b69a4b520"}, {file = "ursa_bbs_signatures-1.0.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:79f410a1f89855a4149af7adecaa22a5f427640f5d093f53670657394a9f9ef4"}, @@ -2766,7 +2662,6 @@ version = "0.10.0" description = "Drop-in replacement for Python UUID in Rust" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "uuid_utils-0.10.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8d5a4508feefec62456cd6a41bcdde458d56827d908f226803b886d22a3d5e63"}, {file = "uuid_utils-0.10.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:dbefc2b9113f9dfe56bdae58301a2b3c53792221410d422826f3d1e3e6555fe7"}, @@ -2803,7 +2698,6 @@ version = "20.29.1" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "virtualenv-20.29.1-py3-none-any.whl", hash = "sha256:4e4cb403c0b0da39e13b46b1b2476e505cb0046b25f242bee80f62bf990b2779"}, {file = "virtualenv-20.29.1.tar.gz", hash = "sha256:b8b8970138d32fb606192cb97f6cd4bb644fa486be9308fb9b63f81091b5dc35"}, @@ -2824,7 +2718,6 @@ version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" -groups = ["main"] files = [ {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, @@ -2836,7 +2729,6 @@ version = "8.6.0" description = "Declarative parsing and validation of HTTP request objects, with built-in support for popular web frameworks, including Flask, Django, Bottle, Tornado, Pyramid, Falcon, and aiohttp." optional = false python-versions = ">=3.8" -groups = ["main"] files = [ {file = "webargs-8.6.0-py3-none-any.whl", hash = "sha256:83da4d7105643d0a50499b06d98a6ade1a330ce66d039eaa51f715172c704aba"}, {file = "webargs-8.6.0.tar.gz", hash = "sha256:b8d098ab92bd74c659eca705afa31d681475f218cb15c1e57271fa2103c0547a"}, @@ -2858,7 +2750,6 @@ version = "1.18.3" description = "Yet another URL library" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, @@ -2954,6 +2845,6 @@ bbs = ["ursa-bbs-signatures"] didcommv2 = ["didcomm-messaging"] [metadata] -lock-version = "2.1" +lock-version = "2.0" python-versions = "^3.12" -content-hash = "cc1de5dbba1f6550873d8aee9b7df0367ebe83606933cb92e341d5b523f47c3b" +content-hash = "1176053f084869dafc9f1754b0eed17985beadc7b99dcbefd8290e86853bac55" diff --git a/pyproject.toml b/pyproject.toml index 8b2299d56d..8f2e6ae327 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ marshmallow = "~3.26.1" nest_asyncio = "~1.6.0" packaging = "^24.2" portalocker = "^3.1.1" -prompt_toolkit = ">=2.0.9,<2.1.0" +prompt_toolkit = ">=2.0.9,<3.1.0" pydid = "^0.5.1" pyjwt = "~2.10.1" pyld = "^2.0.4" From 1208e5806dbfeab26991b20d4846d697b21f3968 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 06:37:58 -0800 Subject: [PATCH 14/76] chore(deps): Update sphinx requirement from ~=8.1.3 to ~=8.2.1 (#3539) Updates the requirements on [sphinx](https://github.com/sphinx-doc/sphinx) to permit the latest version. - [Release notes](https://github.com/sphinx-doc/sphinx/releases) - [Changelog](https://github.com/sphinx-doc/sphinx/blob/v8.2.1/CHANGES.rst) - [Commits](https://github.com/sphinx-doc/sphinx/compare/v8.1.3...v8.2.1) --- updated-dependencies: - dependency-name: sphinx dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index d78d51757e..c71935d4db 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,5 +1,5 @@ # Defining the exact versions for ReadTheDocs that will make sure things don't break -sphinx~=8.1.3 +sphinx~=8.2.1 sphinx-rtd-theme~=3.0.2 readthedocs-sphinx-search~=0.3.2 sphinx-notfound-page~=1.1.0 From 80652d00946f1ce4c409d18cae9cd7e5e9040912 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 15:30:36 -0800 Subject: [PATCH 15/76] chore(deps): Bump ossf/scorecard-action in the all-actions group (#3541) Bumps the all-actions group with 1 update: [ossf/scorecard-action](https://github.com/ossf/scorecard-action). Updates `ossf/scorecard-action` from 2.4.0 to 2.4.1 - [Release notes](https://github.com/ossf/scorecard-action/releases) - [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md) - [Commits](https://github.com/ossf/scorecard-action/compare/v2.4.0...v2.4.1) --- updated-dependencies: - dependency-name: ossf/scorecard-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index acd6e04de1..23ebb6f32e 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -40,7 +40,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@v2.4.0 # was v2.3.1 - 0864cf19026789058feabb7e87baa5f140aac736 + uses: ossf/scorecard-action@v2.4.1 # was v2.3.1 - 0864cf19026789058feabb7e87baa5f140aac736 with: results_file: results.sarif results_format: sarif From e271c0d3b931e690d02c0a492ae31316ff0aeac4 Mon Sep 17 00:00:00 2001 From: Patrick St-Louis <43082425+PatStLouis@users.noreply.github.com> Date: Wed, 26 Feb 2025 13:15:19 -0500 Subject: [PATCH 16/76] Add vcdm 2.0 model and context (#3436) * add vcdm 2.0 model and context Signed-off-by: PatStLouis * add backwards compatibility checks: limit proof type and add issuance date with vcdm 1.1 Signed-off-by: PatStLouis * seperate test fixtures, lint Signed-off-by: PatStLouis * replace issuanceDate tests Signed-off-by: PatStLouis * remove askar issuanceDate sorting Signed-off-by: PatStLouis * rename credential context constant Signed-off-by: PatStLouis * linting Signed-off-by: PatStLouis * updated linting Signed-off-by: PatStLouis * remove askar sorting step Signed-off-by: PatStLouis * add vcdm 2.0 tests, fix presentation route default cryptosuite Signed-off-by: PatStLouis * Fix broken tests, add v2 context to test document loader Signed-off-by: PatStLouis * Lint Signed-off-by: PatStLouis * Debugging unit tests Signed-off-by: PatStLouis * rename test function to v2 Signed-off-by: PatStLouis * add list of support cryptosuites for vcdm 2.0 Signed-off-by: PatStLouis * add list of supported cryptosuites for vcdm 2.0 Signed-off-by: PatStLouis * fix presentation fixture Signed-off-by: PatStLouis * fix created format check Signed-off-by: PatStLouis * fix tset fixtures Signed-off-by: PatStLouis * lint Signed-off-by: PatStLouis * add authentication proof purpose Signed-off-by: PatStLouis * add holder proof type derivation when creating a vp Signed-off-by: PatStLouis * linting Signed-off-by: PatStLouis --------- Signed-off-by: PatStLouis --- acapy_agent/messaging/valid.py | 14 +- .../v2_0/formats/ld_proof/tests/fixtures.py | 68 ++++ .../formats/ld_proof/tests/test_handler.py | 80 +---- acapy_agent/storage/vc_holder/askar.py | 12 +- .../vc_holder/tests/test_askar_vc_holder.py | 4 +- acapy_agent/vc/ld_proofs/constants.py | 1 + .../vc/ld_proofs/document_downloader.py | 1 + .../resources/credentials_v2_context.jsonld | 301 ++++++++++++++++++ acapy_agent/vc/routes.py | 5 +- acapy_agent/vc/tests/contexts/__init__.py | 2 + .../vc/tests/contexts/credentials_v2.py | 274 ++++++++++++++++ acapy_agent/vc/tests/document_loader.py | 3 + acapy_agent/vc/vc_ld/manager.py | 24 ++ acapy_agent/vc/vc_ld/models/credential.py | 61 +++- acapy_agent/vc/vc_ld/models/presentation.py | 3 +- .../vc/vc_ld/tests/test_credential_v2.py | 159 +++++++++ acapy_agent/vc/vc_ld/tests/test_vc_v2.py | 110 +++++++ 17 files changed, 1029 insertions(+), 93 deletions(-) create mode 100644 acapy_agent/protocols/issue_credential/v2_0/formats/ld_proof/tests/fixtures.py create mode 100644 acapy_agent/vc/ld_proofs/resources/credentials_v2_context.jsonld create mode 100644 acapy_agent/vc/tests/contexts/credentials_v2.py create mode 100644 acapy_agent/vc/vc_ld/tests/test_credential_v2.py create mode 100644 acapy_agent/vc/vc_ld/tests/test_vc_v2.py diff --git a/acapy_agent/messaging/valid.py b/acapy_agent/messaging/valid.py index 11f110a5d9..f1cb03544f 100644 --- a/acapy_agent/messaging/valid.py +++ b/acapy_agent/messaging/valid.py @@ -898,7 +898,11 @@ class CredentialContext(Validator): """Credential Context.""" FIRST_CONTEXT = "https://www.w3.org/2018/credentials/v1" - EXAMPLE = [FIRST_CONTEXT, "https://www.w3.org/2018/credentials/examples/v1"] + VALID_CONTEXTS = [ + "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/ns/credentials/v2", + ] + EXAMPLE = [VALID_CONTEXTS[0], "https://www.w3.org/2018/credentials/examples/v1"] def __init__(self) -> None: """Initialize the instance.""" @@ -906,11 +910,13 @@ def __init__(self) -> None: def __call__(self, value): """Validate input value.""" - length = len(value) - if length < 1 or value[0] != CredentialContext.FIRST_CONTEXT: + if not isinstance(value, list): + raise ValidationError("Value must be a non-empty list.") + + if not value or value[0] not in CredentialContext.VALID_CONTEXTS: raise ValidationError( - f"First context must be {CredentialContext.FIRST_CONTEXT}" + f"First context must be one of {CredentialContext.VALID_CONTEXTS}" ) return value diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/ld_proof/tests/fixtures.py b/acapy_agent/protocols/issue_credential/v2_0/formats/ld_proof/tests/fixtures.py new file mode 100644 index 0000000000..02c6205092 --- /dev/null +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/ld_proof/tests/fixtures.py @@ -0,0 +1,68 @@ +TEST_DID_SOV = "did:sov:LjgpST2rjsoxYegQDRm7EL" +TEST_DID_KEY = "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL" + +LD_PROOF_VC_DETAIL = { + "credential": { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/2018/credentials/examples/v1", + ], + "type": ["VerifiableCredential", "UniversityDegreeCredential"], + "credentialSubject": {"test": "key"}, + "issuanceDate": "2021-04-12", + "issuer": TEST_DID_KEY, + }, + "options": { + "proofType": "Ed25519Signature2018", + "created": "2019-12-11T03:50:55", + }, +} +LD_PROOF_VC_DETAIL_BBS = { + "credential": { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/2018/credentials/examples/v1", + ], + "type": ["VerifiableCredential", "UniversityDegreeCredential"], + "credentialSubject": {"test": "key"}, + "issuanceDate": "2021-04-12", + "issuer": TEST_DID_KEY, + }, + "options": { + "proofType": "BbsBlsSignature2020", + "created": "2019-12-11T03:50:55", + }, +} +LD_PROOF_VC_DETAIL_ED25519_2020 = { + "credential": { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/2018/credentials/examples/v1", + ], + "type": ["VerifiableCredential", "UniversityDegreeCredential"], + "credentialSubject": {"test": "key"}, + "issuanceDate": "2021-04-12", + "issuer": TEST_DID_KEY, + }, + "options": { + "proofType": "Ed25519Signature2020", + "created": "2019-12-11T03:50:55", + }, +} +LD_PROOF_VC = { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/2018/credentials/examples/v1", + ], + "type": ["VerifiableCredential", "UniversityDegreeCredential"], + "credentialSubject": {"test": "key"}, + "issuanceDate": "2021-04-12", + "issuer": TEST_DID_KEY, + "proof": { + "proofPurpose": "assertionMethod", + "created": "2019-12-11T03:50:55", + "type": "Ed25519Signature2018", + "verificationMethod": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL#z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL", + "jws": "eyJhbGciOiAiRWREU0EiLCAiYjY0IjogZmFsc2UsICJjcml0IjogWyJiNjQiXX0..Q6amIrxGiSbM7Ce6DxlfwLCjVcYyclas8fMxaecspXFUcFW9DAAxKzgHx93FWktnlZjM_biitkMgZdStgvivAQ", + }, +} diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/ld_proof/tests/test_handler.py b/acapy_agent/protocols/issue_credential/v2_0/formats/ld_proof/tests/test_handler.py index 33a92abbc9..b72e1175bd 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/ld_proof/tests/test_handler.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/ld_proof/tests/test_handler.py @@ -43,75 +43,12 @@ from ..handler import LOGGER as LD_PROOF_LOGGER from ..handler import LDProofCredFormatHandler from ..models.cred_detail import LDProofVCDetail - -TEST_DID_SOV = "did:sov:LjgpST2rjsoxYegQDRm7EL" -TEST_DID_KEY = "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL" - -LD_PROOF_VC_DETAIL = { - "credential": { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://www.w3.org/2018/credentials/examples/v1", - ], - "type": ["VerifiableCredential", "UniversityDegreeCredential"], - "credentialSubject": {"test": "key"}, - "issuanceDate": "2021-04-12", - "issuer": TEST_DID_KEY, - }, - "options": { - "proofType": "Ed25519Signature2018", - "created": "2019-12-11T03:50:55", - }, -} -LD_PROOF_VC_DETAIL_BBS = { - "credential": { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://www.w3.org/2018/credentials/examples/v1", - ], - "type": ["VerifiableCredential", "UniversityDegreeCredential"], - "credentialSubject": {"test": "key"}, - "issuanceDate": "2021-04-12", - "issuer": TEST_DID_KEY, - }, - "options": { - "proofType": "BbsBlsSignature2020", - "created": "2019-12-11T03:50:55", - }, -} -LD_PROOF_VC_DETAIL_ED25519_2020 = { - "credential": { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://www.w3.org/2018/credentials/examples/v1", - ], - "type": ["VerifiableCredential", "UniversityDegreeCredential"], - "credentialSubject": {"test": "key"}, - "issuanceDate": "2021-04-12", - "issuer": TEST_DID_KEY, - }, - "options": { - "proofType": "Ed25519Signature2020", - "created": "2019-12-11T03:50:55", - }, -} -LD_PROOF_VC = { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://www.w3.org/2018/credentials/examples/v1", - ], - "type": ["VerifiableCredential", "UniversityDegreeCredential"], - "credentialSubject": {"test": "key"}, - "issuanceDate": "2021-04-12", - "issuer": TEST_DID_KEY, - "proof": { - "proofPurpose": "assertionMethod", - "created": "2019-12-11T03:50:55", - "type": "Ed25519Signature2018", - "verificationMethod": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL#z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL", - "jws": "eyJhbGciOiAiRWREU0EiLCAiYjY0IjogZmFsc2UsICJjcml0IjogWyJiNjQiXX0..Q6amIrxGiSbM7Ce6DxlfwLCjVcYyclas8fMxaecspXFUcFW9DAAxKzgHx93FWktnlZjM_biitkMgZdStgvivAQ", - }, -} +from .fixtures import ( + LD_PROOF_VC_DETAIL, + LD_PROOF_VC_DETAIL_BBS, + LD_PROOF_VC_DETAIL_ED25519_2020, + LD_PROOF_VC, +) class TestV20LDProofCredFormatHandler(IsolatedAsyncioTestCase): @@ -166,7 +103,7 @@ async def test_validate_fields(self): incorrect_detail = { **LD_PROOF_VC_DETAIL, - "credential": {**LD_PROOF_VC_DETAIL["credential"], "issuanceDate": None}, + "credential": {**LD_PROOF_VC_DETAIL["credential"], "credentialSubject": None}, } # test incorrect proposal @@ -184,8 +121,7 @@ async def test_validate_fields(self): # test incorrect cred with self.assertRaises(ValidationError): incorrect_cred = LD_PROOF_VC.copy() - incorrect_cred.pop("issuanceDate") - + incorrect_cred.pop("credentialSubject") self.handler.validate_fields(CRED_20_ISSUE, incorrect_cred) async def test_get_ld_proof_detail_record(self): diff --git a/acapy_agent/storage/vc_holder/askar.py b/acapy_agent/storage/vc_holder/askar.py index bf4874a65f..3988a58237 100644 --- a/acapy_agent/storage/vc_holder/askar.py +++ b/acapy_agent/storage/vc_holder/askar.py @@ -3,9 +3,6 @@ import json from typing import Mapping, Optional, Sequence -from dateutil.parser import ParserError -from dateutil.parser import parse as dateutil_parser - from ...askar.profile import AskarProfile from ..askar import AskarStorage, AskarStorageSearch, AskarStorageSearchSession from ..record import StorageRecord @@ -174,14 +171,7 @@ async def fetch(self, max_count: Optional[int] = None) -> Sequence[VCRecord]: """ rows = await self._search.fetch(max_count) records = [storage_to_vc_record(r) for r in rows] - try: - records.sort( - key=lambda v: dateutil_parser(v.cred_value.get("issuanceDate")), - reverse=True, - ) - return records - except ParserError: - return records + return records def storage_to_vc_record(record: StorageRecord) -> VCRecord: diff --git a/acapy_agent/storage/vc_holder/tests/test_askar_vc_holder.py b/acapy_agent/storage/vc_holder/tests/test_askar_vc_holder.py index c3a2639dec..23be81084b 100644 --- a/acapy_agent/storage/vc_holder/tests/test_askar_vc_holder.py +++ b/acapy_agent/storage/vc_holder/tests/test_askar_vc_holder.py @@ -268,11 +268,11 @@ async def test_sorting_vcrecord(holder: VCHolder): }, ) await holder.store_credential(record_c) - expected = [record_b, record_a, record_c] + # expected = [record_b, record_a, record_c] search = holder.search_credentials() rows = await search.fetch() - assert rows == expected + assert rows # == expected @pytest.mark.asyncio diff --git a/acapy_agent/vc/ld_proofs/constants.py b/acapy_agent/vc/ld_proofs/constants.py index 03af17dfc9..7ff04ba1ba 100644 --- a/acapy_agent/vc/ld_proofs/constants.py +++ b/acapy_agent/vc/ld_proofs/constants.py @@ -6,6 +6,7 @@ SECURITY_CONTEXT_URL = SECURITY_CONTEXT_V2_URL DID_V1_CONTEXT_URL = "https://www.w3.org/ns/did/v1" CREDENTIALS_CONTEXT_V1_URL = "https://www.w3.org/2018/credentials/v1" +CREDENTIALS_CONTEXT_V2_URL = "https://www.w3.org/ns/credentials/v2" SECURITY_CONTEXT_BBS_URL = "https://w3id.org/security/bbs/v1" SECURITY_CONTEXT_ED25519_2020_URL = "https://w3id.org/security/suites/ed25519-2020/v1" SECURITY_CONTEXT_MULTIKEY_URL = "https://w3id.org/security/multikey/v1" diff --git a/acapy_agent/vc/ld_proofs/document_downloader.py b/acapy_agent/vc/ld_proofs/document_downloader.py index 553e00dd39..7f7ffbeec5 100644 --- a/acapy_agent/vc/ld_proofs/document_downloader.py +++ b/acapy_agent/vc/ld_proofs/document_downloader.py @@ -40,6 +40,7 @@ class StaticCacheJsonLdDownloader: CONTEXT_FILE_MAPPING = { "https://www.w3.org/2018/credentials/v1": "credentials_context.jsonld", + "https://www.w3.org/ns/credentials/v2": "credentials_v2_context.jsonld", "https://w3id.org/vc/status-list/2021/v1": "status_list_context.jsonld", "https://www.w3.org/ns/did/v1": "did_documents_context.jsonld", "https://w3id.org/security/v1": "security-v1-context.jsonld", diff --git a/acapy_agent/vc/ld_proofs/resources/credentials_v2_context.jsonld b/acapy_agent/vc/ld_proofs/resources/credentials_v2_context.jsonld new file mode 100644 index 0000000000..bb4a78b630 --- /dev/null +++ b/acapy_agent/vc/ld_proofs/resources/credentials_v2_context.jsonld @@ -0,0 +1,301 @@ +{ + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "description": "https://schema.org/description", + "digestMultibase": { + "@id": "https://w3id.org/security#digestMultibase", + "@type": "https://w3id.org/security#multibase" + }, + "digestSRI": { + "@id": "https://www.w3.org/2018/credentials#digestSRI", + "@type": "https://www.w3.org/2018/credentials#sriString" + }, + "mediaType": { + "@id": "https://schema.org/encodingFormat" + }, + "name": "https://schema.org/name", + "VerifiableCredential": { + "@id": "https://www.w3.org/2018/credentials#VerifiableCredential", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "confidenceMethod": { + "@id": "https://www.w3.org/2018/credentials#confidenceMethod", + "@type": "@id" + }, + "credentialSchema": { + "@id": "https://www.w3.org/2018/credentials#credentialSchema", + "@type": "@id" + }, + "credentialStatus": { + "@id": "https://www.w3.org/2018/credentials#credentialStatus", + "@type": "@id" + }, + "credentialSubject": { + "@id": "https://www.w3.org/2018/credentials#credentialSubject", + "@type": "@id" + }, + "description": "https://schema.org/description", + "evidence": { + "@id": "https://www.w3.org/2018/credentials#evidence", + "@type": "@id" + }, + "issuer": { + "@id": "https://www.w3.org/2018/credentials#issuer", + "@type": "@id" + }, + "name": "https://schema.org/name", + "proof": { + "@id": "https://w3id.org/security#proof", + "@type": "@id", + "@container": "@graph" + }, + "refreshService": { + "@id": "https://www.w3.org/2018/credentials#refreshService", + "@type": "@id" + }, + "relatedResource": { + "@id": "https://www.w3.org/2018/credentials#relatedResource", + "@type": "@id" + }, + "renderMethod": { + "@id": "https://www.w3.org/2018/credentials#renderMethod", + "@type": "@id" + }, + "termsOfUse": { + "@id": "https://www.w3.org/2018/credentials#termsOfUse", + "@type": "@id" + }, + "validFrom": { + "@id": "https://www.w3.org/2018/credentials#validFrom", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "validUntil": { + "@id": "https://www.w3.org/2018/credentials#validUntil", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + } + } + }, + "EnvelopedVerifiableCredential": "https://www.w3.org/2018/credentials#EnvelopedVerifiableCredential", + "VerifiablePresentation": { + "@id": "https://www.w3.org/2018/credentials#VerifiablePresentation", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "holder": { + "@id": "https://www.w3.org/2018/credentials#holder", + "@type": "@id" + }, + "proof": { + "@id": "https://w3id.org/security#proof", + "@type": "@id", + "@container": "@graph" + }, + "termsOfUse": { + "@id": "https://www.w3.org/2018/credentials#termsOfUse", + "@type": "@id" + }, + "verifiableCredential": { + "@id": "https://www.w3.org/2018/credentials#verifiableCredential", + "@type": "@id", + "@container": "@graph", + "@context": null + } + } + }, + "EnvelopedVerifiablePresentation": "https://www.w3.org/2018/credentials#EnvelopedVerifiablePresentation", + "JsonSchemaCredential": "https://www.w3.org/2018/credentials#JsonSchemaCredential", + "JsonSchema": { + "@id": "https://www.w3.org/2018/credentials#JsonSchema", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "jsonSchema": { + "@id": "https://www.w3.org/2018/credentials#jsonSchema", + "@type": "@json" + } + } + }, + "BitstringStatusListCredential": "https://www.w3.org/ns/credentials/status#BitstringStatusListCredential", + "BitstringStatusList": { + "@id": "https://www.w3.org/ns/credentials/status#BitstringStatusList", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "encodedList": { + "@id": "https://www.w3.org/ns/credentials/status#encodedList", + "@type": "https://w3id.org/security#multibase" + }, + "statusMessage": { + "@id": "https://www.w3.org/ns/credentials/status#statusMessage", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "message": "https://www.w3.org/ns/credentials/status#message", + "status": "https://www.w3.org/ns/credentials/status#status" + } + }, + "statusPurpose": "https://www.w3.org/ns/credentials/status#statusPurpose", + "statusReference": { + "@id": "https://www.w3.org/ns/credentials/status#statusReference", + "@type": "@id" + }, + "statusSize": { + "@id": "https://www.w3.org/ns/credentials/status#statusSize", + "@type": "https://www.w3.org/2001/XMLSchema#positiveInteger" + }, + "ttl": "https://www.w3.org/ns/credentials/status#ttl" + } + }, + "BitstringStatusListEntry": { + "@id": "https://www.w3.org/ns/credentials/status#BitstringStatusListEntry", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "statusListCredential": { + "@id": "https://www.w3.org/ns/credentials/status#statusListCredential", + "@type": "@id" + }, + "statusListIndex": "https://www.w3.org/ns/credentials/status#statusListIndex", + "statusPurpose": "https://www.w3.org/ns/credentials/status#statusPurpose" + } + }, + "DataIntegrityProof": { + "@id": "https://w3id.org/security#DataIntegrityProof", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "challenge": "https://w3id.org/security#challenge", + "created": { + "@id": "http://purl.org/dc/terms/created", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "cryptosuite": { + "@id": "https://w3id.org/security#cryptosuite", + "@type": "https://w3id.org/security#cryptosuiteString" + }, + "domain": "https://w3id.org/security#domain", + "expires": { + "@id": "https://w3id.org/security#expiration", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "nonce": "https://w3id.org/security#nonce", + "previousProof": { + "@id": "https://w3id.org/security#previousProof", + "@type": "@id" + }, + "proofPurpose": { + "@id": "https://w3id.org/security#proofPurpose", + "@type": "@vocab", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "assertionMethod": { + "@id": "https://w3id.org/security#assertionMethod", + "@type": "@id", + "@container": "@set" + }, + "authentication": { + "@id": "https://w3id.org/security#authenticationMethod", + "@type": "@id", + "@container": "@set" + }, + "capabilityDelegation": { + "@id": "https://w3id.org/security#capabilityDelegationMethod", + "@type": "@id", + "@container": "@set" + }, + "capabilityInvocation": { + "@id": "https://w3id.org/security#capabilityInvocationMethod", + "@type": "@id", + "@container": "@set" + }, + "keyAgreement": { + "@id": "https://w3id.org/security#keyAgreementMethod", + "@type": "@id", + "@container": "@set" + } + } + }, + "proofValue": { + "@id": "https://w3id.org/security#proofValue", + "@type": "https://w3id.org/security#multibase" + }, + "verificationMethod": { + "@id": "https://w3id.org/security#verificationMethod", + "@type": "@id" + } + } + }, + "...": { + "@id": "https://www.iana.org/assignments/jwt#..." + }, + "_sd": { + "@id": "https://www.iana.org/assignments/jwt#_sd", + "@type": "@json" + }, + "_sd_alg": { + "@id": "https://www.iana.org/assignments/jwt#_sd_alg" + }, + "aud": { + "@id": "https://www.iana.org/assignments/jwt#aud", + "@type": "@id" + }, + "cnf": { + "@id": "https://www.iana.org/assignments/jwt#cnf", + "@context": { + "@protected": true, + "kid": { + "@id": "https://www.iana.org/assignments/jwt#kid", + "@type": "@id" + }, + "jwk": { + "@id": "https://www.iana.org/assignments/jwt#jwk", + "@type": "@json" + } + } + }, + "exp": { + "@id": "https://www.iana.org/assignments/jwt#exp", + "@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger" + }, + "iat": { + "@id": "https://www.iana.org/assignments/jwt#iat", + "@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger" + }, + "iss": { + "@id": "https://www.iana.org/assignments/jose#iss", + "@type": "@id" + }, + "jku": { + "@id": "https://www.iana.org/assignments/jose#jku", + "@type": "@id" + }, + "kid": { + "@id": "https://www.iana.org/assignments/jose#kid", + "@type": "@id" + }, + "nbf": { + "@id": "https://www.iana.org/assignments/jwt#nbf", + "@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger" + }, + "sub": { + "@id": "https://www.iana.org/assignments/jose#sub", + "@type": "@id" + }, + "x5u": { + "@id": "https://www.iana.org/assignments/jose#x5u", + "@type": "@id" + } + } +} \ No newline at end of file diff --git a/acapy_agent/vc/routes.py b/acapy_agent/vc/routes.py index 1993fe4731..9977d90d5c 100644 --- a/acapy_agent/vc/routes.py +++ b/acapy_agent/vc/routes.py @@ -195,7 +195,7 @@ async def prove_presentation_route(request: web.BaseRequest): options = {} if "options" not in body else body["options"] # We derive the proofType from the holder DID if not provided in options - if not options.get("proofType", None): + if not options.get("proofType", None) and presentation.get("holder"): holder = presentation["holder"] did = holder if isinstance(holder, str) else holder["id"] async with context.session() as session: @@ -210,6 +210,9 @@ async def prove_presentation_route(request: web.BaseRequest): elif key_type == "p256": options["proofType"] = "EcdsaSecp256r1Signature2019" + else: + options["proofType"] = options.get("proofType") or "Ed25519Signature2020" + presentation = VerifiablePresentation.deserialize(presentation) options = LDProofVCOptions.deserialize(options) vp = await manager.prove(presentation, options) diff --git a/acapy_agent/vc/tests/contexts/__init__.py b/acapy_agent/vc/tests/contexts/__init__.py index 7d6acb271e..de43b411e2 100644 --- a/acapy_agent/vc/tests/contexts/__init__.py +++ b/acapy_agent/vc/tests/contexts/__init__.py @@ -1,6 +1,7 @@ from .bbs_v1 import BBS_V1 from .citizenship_v1 import CITIZENSHIP_V1 from .credentials_v1 import CREDENTIALS_V1 +from .credentials_v2 import CREDENTIALS_V2 from .did_v1 import DID_V1 from .dif_presentation_submission_v1 import DIF_PRESENTATION_SUBMISSION_V1 from .ed25519_2020_v1 import ED25519_2020_V1 @@ -23,6 +24,7 @@ "ED25519_2020_V1", "MULTIKEY_V1", "CREDENTIALS_V1", + "CREDENTIALS_V2", "CITIZENSHIP_V1", "VACCINATION_V1", "EXAMPLES_V1", diff --git a/acapy_agent/vc/tests/contexts/credentials_v2.py b/acapy_agent/vc/tests/contexts/credentials_v2.py new file mode 100644 index 0000000000..ea21865feb --- /dev/null +++ b/acapy_agent/vc/tests/contexts/credentials_v2.py @@ -0,0 +1,274 @@ +CREDENTIALS_V2 = { + "@context": { + "@protected": True, + "id": "@id", + "type": "@type", + "description": "https://schema.org/description", + "digestMultibase": { + "@id": "https://w3id.org/security#digestMultibase", + "@type": "https://w3id.org/security#multibase", + }, + "digestSRI": { + "@id": "https://www.w3.org/2018/credentials#digestSRI", + "@type": "https://www.w3.org/2018/credentials#sriString", + }, + "mediaType": {"@id": "https://schema.org/encodingFormat"}, + "name": "https://schema.org/name", + "VerifiableCredential": { + "@id": "https://www.w3.org/2018/credentials#VerifiableCredential", + "@context": { + "@protected": True, + "id": "@id", + "type": "@type", + "confidenceMethod": { + "@id": "https://www.w3.org/2018/credentials#confidenceMethod", + "@type": "@id", + }, + "credentialSchema": { + "@id": "https://www.w3.org/2018/credentials#credentialSchema", + "@type": "@id", + }, + "credentialStatus": { + "@id": "https://www.w3.org/2018/credentials#credentialStatus", + "@type": "@id", + }, + "credentialSubject": { + "@id": "https://www.w3.org/2018/credentials#credentialSubject", + "@type": "@id", + }, + "description": "https://schema.org/description", + "evidence": { + "@id": "https://www.w3.org/2018/credentials#evidence", + "@type": "@id", + }, + "issuer": { + "@id": "https://www.w3.org/2018/credentials#issuer", + "@type": "@id", + }, + "name": "https://schema.org/name", + "proof": { + "@id": "https://w3id.org/security#proof", + "@type": "@id", + "@container": "@graph", + }, + "refreshService": { + "@id": "https://www.w3.org/2018/credentials#refreshService", + "@type": "@id", + }, + "relatedResource": { + "@id": "https://www.w3.org/2018/credentials#relatedResource", + "@type": "@id", + }, + "renderMethod": { + "@id": "https://www.w3.org/2018/credentials#renderMethod", + "@type": "@id", + }, + "termsOfUse": { + "@id": "https://www.w3.org/2018/credentials#termsOfUse", + "@type": "@id", + }, + "validFrom": { + "@id": "https://www.w3.org/2018/credentials#validFrom", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + }, + "validUntil": { + "@id": "https://www.w3.org/2018/credentials#validUntil", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + }, + }, + }, + "EnvelopedVerifiableCredential": "https://www.w3.org/2018/credentials#EnvelopedVerifiableCredential", + "VerifiablePresentation": { + "@id": "https://www.w3.org/2018/credentials#VerifiablePresentation", + "@context": { + "@protected": True, + "id": "@id", + "type": "@type", + "holder": { + "@id": "https://www.w3.org/2018/credentials#holder", + "@type": "@id", + }, + "proof": { + "@id": "https://w3id.org/security#proof", + "@type": "@id", + "@container": "@graph", + }, + "termsOfUse": { + "@id": "https://www.w3.org/2018/credentials#termsOfUse", + "@type": "@id", + }, + "verifiableCredential": { + "@id": "https://www.w3.org/2018/credentials#verifiableCredential", + "@type": "@id", + "@container": "@graph", + "@context": None, + }, + }, + }, + "EnvelopedVerifiablePresentation": "https://www.w3.org/2018/credentials#EnvelopedVerifiablePresentation", + "JsonSchemaCredential": "https://www.w3.org/2018/credentials#JsonSchemaCredential", + "JsonSchema": { + "@id": "https://www.w3.org/2018/credentials#JsonSchema", + "@context": { + "@protected": True, + "id": "@id", + "type": "@type", + "jsonSchema": { + "@id": "https://www.w3.org/2018/credentials#jsonSchema", + "@type": "@json", + }, + }, + }, + "BitstringStatusListCredential": "https://www.w3.org/ns/credentials/status#BitstringStatusListCredential", + "BitstringStatusList": { + "@id": "https://www.w3.org/ns/credentials/status#BitstringStatusList", + "@context": { + "@protected": True, + "id": "@id", + "type": "@type", + "encodedList": { + "@id": "https://www.w3.org/ns/credentials/status#encodedList", + "@type": "https://w3id.org/security#multibase", + }, + "statusMessage": { + "@id": "https://www.w3.org/ns/credentials/status#statusMessage", + "@context": { + "@protected": True, + "id": "@id", + "type": "@type", + "message": "https://www.w3.org/ns/credentials/status#message", + "status": "https://www.w3.org/ns/credentials/status#status", + }, + }, + "statusPurpose": "https://www.w3.org/ns/credentials/status#statusPurpose", + "statusReference": { + "@id": "https://www.w3.org/ns/credentials/status#statusReference", + "@type": "@id", + }, + "statusSize": { + "@id": "https://www.w3.org/ns/credentials/status#statusSize", + "@type": "https://www.w3.org/2001/XMLSchema#positiveInteger", + }, + "ttl": "https://www.w3.org/ns/credentials/status#ttl", + }, + }, + "BitstringStatusListEntry": { + "@id": "https://www.w3.org/ns/credentials/status#BitstringStatusListEntry", + "@context": { + "@protected": True, + "id": "@id", + "type": "@type", + "statusListCredential": { + "@id": "https://www.w3.org/ns/credentials/status#statusListCredential", + "@type": "@id", + }, + "statusListIndex": "https://www.w3.org/ns/credentials/status#statusListIndex", + "statusPurpose": "https://www.w3.org/ns/credentials/status#statusPurpose", + }, + }, + "DataIntegrityProof": { + "@id": "https://w3id.org/security#DataIntegrityProof", + "@context": { + "@protected": True, + "id": "@id", + "type": "@type", + "challenge": "https://w3id.org/security#challenge", + "created": { + "@id": "http://purl.org/dc/terms/created", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + }, + "cryptosuite": { + "@id": "https://w3id.org/security#cryptosuite", + "@type": "https://w3id.org/security#cryptosuiteString", + }, + "domain": "https://w3id.org/security#domain", + "expires": { + "@id": "https://w3id.org/security#expiration", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + }, + "nonce": "https://w3id.org/security#nonce", + "previousProof": { + "@id": "https://w3id.org/security#previousProof", + "@type": "@id", + }, + "proofPurpose": { + "@id": "https://w3id.org/security#proofPurpose", + "@type": "@vocab", + "@context": { + "@protected": True, + "id": "@id", + "type": "@type", + "assertionMethod": { + "@id": "https://w3id.org/security#assertionMethod", + "@type": "@id", + "@container": "@set", + }, + "authentication": { + "@id": "https://w3id.org/security#authenticationMethod", + "@type": "@id", + "@container": "@set", + }, + "capabilityDelegation": { + "@id": "https://w3id.org/security#capabilityDelegationMethod", + "@type": "@id", + "@container": "@set", + }, + "capabilityInvocation": { + "@id": "https://w3id.org/security#capabilityInvocationMethod", + "@type": "@id", + "@container": "@set", + }, + "keyAgreement": { + "@id": "https://w3id.org/security#keyAgreementMethod", + "@type": "@id", + "@container": "@set", + }, + }, + }, + "proofValue": { + "@id": "https://w3id.org/security#proofValue", + "@type": "https://w3id.org/security#multibase", + }, + "verificationMethod": { + "@id": "https://w3id.org/security#verificationMethod", + "@type": "@id", + }, + }, + }, + "...": {"@id": "https://www.iana.org/assignments/jwt#..."}, + "_sd": {"@id": "https://www.iana.org/assignments/jwt#_sd", "@type": "@json"}, + "_sd_alg": {"@id": "https://www.iana.org/assignments/jwt#_sd_alg"}, + "aud": {"@id": "https://www.iana.org/assignments/jwt#aud", "@type": "@id"}, + "cnf": { + "@id": "https://www.iana.org/assignments/jwt#cnf", + "@context": { + "@protected": True, + "kid": { + "@id": "https://www.iana.org/assignments/jwt#kid", + "@type": "@id", + }, + "jwk": { + "@id": "https://www.iana.org/assignments/jwt#jwk", + "@type": "@json", + }, + }, + }, + "exp": { + "@id": "https://www.iana.org/assignments/jwt#exp", + "@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger", + }, + "iat": { + "@id": "https://www.iana.org/assignments/jwt#iat", + "@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger", + }, + "iss": {"@id": "https://www.iana.org/assignments/jose#iss", "@type": "@id"}, + "jku": {"@id": "https://www.iana.org/assignments/jose#jku", "@type": "@id"}, + "kid": {"@id": "https://www.iana.org/assignments/jose#kid", "@type": "@id"}, + "nbf": { + "@id": "https://www.iana.org/assignments/jwt#nbf", + "@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger", + }, + "sub": {"@id": "https://www.iana.org/assignments/jose#sub", "@type": "@id"}, + "x5u": {"@id": "https://www.iana.org/assignments/jose#x5u", "@type": "@id"}, + } +} diff --git a/acapy_agent/vc/tests/document_loader.py b/acapy_agent/vc/tests/document_loader.py index 7204f27c9d..04cccd5f83 100644 --- a/acapy_agent/vc/tests/document_loader.py +++ b/acapy_agent/vc/tests/document_loader.py @@ -1,5 +1,6 @@ from ..ld_proofs.constants import ( CREDENTIALS_CONTEXT_V1_URL, + CREDENTIALS_CONTEXT_V2_URL, DID_V1_CONTEXT_URL, SECURITY_CONTEXT_BBS_URL, SECURITY_CONTEXT_ED25519_2020_URL, @@ -12,6 +13,7 @@ BBS_V1, CITIZENSHIP_V1, CREDENTIALS_V1, + CREDENTIALS_V2, DID_V1, DIF_PRESENTATION_SUBMISSION_V1, ED25519_2020_V1, @@ -49,6 +51,7 @@ SECURITY_CONTEXT_V3_URL: SECURITY_V3_UNSTABLE, DID_V1_CONTEXT_URL: DID_V1, CREDENTIALS_CONTEXT_V1_URL: CREDENTIALS_V1, + CREDENTIALS_CONTEXT_V2_URL: CREDENTIALS_V2, SECURITY_CONTEXT_BBS_URL: BBS_V1, SECURITY_CONTEXT_ED25519_2020_URL: ED25519_2020_V1, SECURITY_CONTEXT_MULTIKEY_URL: MULTIKEY_V1, diff --git a/acapy_agent/vc/vc_ld/manager.py b/acapy_agent/vc/vc_ld/manager.py index 9ade719e4c..46ea6fad36 100644 --- a/acapy_agent/vc/vc_ld/manager.py +++ b/acapy_agent/vc/vc_ld/manager.py @@ -1,5 +1,6 @@ """Manager for performing Linked Data Proof signatures over JSON-LD formatted W3C VCs.""" +from datetime import datetime, timezone from typing import Dict, List, Optional, Type, Union, cast from pyld import jsonld @@ -18,6 +19,8 @@ from ...wallet.error import WalletNotFoundError from ...wallet.key_type import BLS12381G2, ED25519, P256, KeyType from ..ld_proofs.constants import ( + CREDENTIALS_CONTEXT_V1_URL, + CREDENTIALS_CONTEXT_V2_URL, SECURITY_CONTEXT_BBS_URL, SECURITY_CONTEXT_ED25519_2020_URL, ) @@ -59,6 +62,10 @@ CredentialIssuancePurpose.term, AuthenticationProofPurpose.term, } +SUPPORTED_V2_ISSUANCE_PROOF_TYPES = [ + Ed25519Signature2020.signature_type, + BbsBlsSignature2020.signature_type, +] SIGNATURE_SUITE_KEY_TYPE_MAPPING: Dict[SignatureTypes, KeyType] = { Ed25519Signature2018: ED25519, Ed25519Signature2020: ED25519, @@ -266,6 +273,15 @@ async def prepare_credential( holder_did: Optional[str] = None, ) -> VerifiableCredential: """Prepare a credential for issuance.""" + # Limit VCDM 2.0 with Ed25519Signature2020 + if ( + credential.context_urls[0] == CREDENTIALS_CONTEXT_V2_URL + and options.proof_type not in SUPPORTED_V2_ISSUANCE_PROOF_TYPES + ): + raise VcLdpManagerError( + f"Supported VC 2.0 proof types are: {SUPPORTED_V2_ISSUANCE_PROOF_TYPES}." + ) + # Add BBS context if not present yet if ( options.proof_type == BbsBlsSignature2020.signature_type @@ -289,6 +305,14 @@ async def prepare_credential( if isinstance(subject, list): subject = subject[0] + if ( + not credential.issuance_date + and credential.context_urls[0] == CREDENTIALS_CONTEXT_V1_URL + ): + credential.issuance_date = str( + datetime.now(timezone.utc).isoformat("T", "seconds") + ) + if not subject: raise VcLdpManagerError("Credential subject is required") diff --git a/acapy_agent/vc/vc_ld/models/credential.py b/acapy_agent/vc/vc_ld/models/credential.py index 8ba27a9a4b..540e3c593d 100644 --- a/acapy_agent/vc/vc_ld/models/credential.py +++ b/acapy_agent/vc/vc_ld/models/credential.py @@ -26,6 +26,7 @@ ) from ...ld_proofs.constants import ( CREDENTIALS_CONTEXT_V1_URL, + CREDENTIALS_CONTEXT_V2_URL, VERIFIABLE_CREDENTIAL_TYPE, ) from .linked_data_proof import LDProof, LinkedDataProofSchema @@ -47,6 +48,8 @@ def __init__( issuer: Optional[Union[dict, str]] = None, issuance_date: Optional[str] = None, expiration_date: Optional[str] = None, + valid_from: Optional[str] = None, + valid_until: Optional[str] = None, credential_subject: Optional[Union[dict, List[dict]]] = None, credential_status: Optional[Union[dict, List[dict]]] = None, proof: Optional[Union[dict, LDProof]] = None, @@ -63,6 +66,8 @@ def __init__( # TODO: proper date parsing self._issuance_date = issuance_date self._expiration_date = expiration_date + self._valid_from = valid_from + self._valid_until = valid_until self._proof = proof @@ -79,7 +84,7 @@ def context(self, context: List[Union[str, dict]]): First item must be credentials v1 url """ - assert context[0] == CREDENTIALS_CONTEXT_V1_URL + assert context[0] in [CREDENTIALS_CONTEXT_V1_URL, CREDENTIALS_CONTEXT_V2_URL] self._context = context @@ -195,6 +200,36 @@ def expiration_date(self, date: Union[str, datetime, None]): self._expiration_date = date + @property + def valid_from(self): + """Getter for valid from date.""" + return self._valid_from + + @valid_from.setter + def valid_from(self, date: Union[str, datetime]): + """Setter for valid from date.""" + if isinstance(date, datetime): + if not date.tzinfo: + date = date.replace(tzinfo=tz.UTC) + date = date.isoformat() + + self._valid_from = date + + @property + def valid_until(self): + """Getter for valid until date.""" + return self._valid_until + + @valid_until.setter + def valid_until(self, date: Union[str, datetime, None]): + """Setter for valid until date.""" + if isinstance(date, datetime): + if not date.tzinfo: + date = date.replace(tzinfo=tz.UTC) + date = date.isoformat() + + self._valid_until = date + @property def credential_subject_ids(self) -> List[str]: """Getter for credential subject ids.""" @@ -260,6 +295,8 @@ def __eq__(self, o: object) -> bool: and self.issuer == o.issuer and self.issuance_date == o.issuance_date and self.expiration_date == o.expiration_date + and self.valid_from == o.valid_from + and self.valid_until == o.valid_until and self.credential_subject == o.credential_subject and self.credential_status == o.credential_status and self.proof == o.proof @@ -325,7 +362,7 @@ class Meta: issuance_date = fields.Str( data_key="issuanceDate", - required=True, + required=False, validate=RFC3339_DATETIME_VALIDATE, metadata={ "description": "The issuance date", @@ -343,6 +380,26 @@ class Meta: }, ) + valid_from = fields.Str( + data_key="validFrom", + required=False, + validate=RFC3339_DATETIME_VALIDATE, + metadata={ + "description": "The valid from date", + "example": RFC3339_DATETIME_EXAMPLE, + }, + ) + + valid_until = fields.Str( + data_key="validUntil", + required=False, + validate=RFC3339_DATETIME_VALIDATE, + metadata={ + "description": "The valid until date", + "example": RFC3339_DATETIME_EXAMPLE, + }, + ) + credential_subject = DictOrDictListField( required=True, data_key="credentialSubject", diff --git a/acapy_agent/vc/vc_ld/models/presentation.py b/acapy_agent/vc/vc_ld/models/presentation.py index 06d437f743..e288a77e84 100644 --- a/acapy_agent/vc/vc_ld/models/presentation.py +++ b/acapy_agent/vc/vc_ld/models/presentation.py @@ -16,6 +16,7 @@ ) from ...ld_proofs.constants import ( CREDENTIALS_CONTEXT_V1_URL, + CREDENTIALS_CONTEXT_V2_URL, VERIFIABLE_PRESENTATION_TYPE, ) from .linked_data_proof import LDProof, LinkedDataProofSchema @@ -61,7 +62,7 @@ def context(self, context: List[Union[str, dict]]): First item must be credentials v1 url """ - assert context[0] == CREDENTIALS_CONTEXT_V1_URL + assert context[0] in [CREDENTIALS_CONTEXT_V1_URL, CREDENTIALS_CONTEXT_V2_URL] self._context = context diff --git a/acapy_agent/vc/vc_ld/tests/test_credential_v2.py b/acapy_agent/vc/vc_ld/tests/test_credential_v2.py new file mode 100644 index 0000000000..1c3795fb9e --- /dev/null +++ b/acapy_agent/vc/vc_ld/tests/test_credential_v2.py @@ -0,0 +1,159 @@ +from ...ld_proofs import DocumentVerificationResult, ProofResult, PurposeResult + +CREDENTIAL_V2_TEMPLATE = { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://w3id.org/security/suites/ed25519-2020/v1", + ], + "type": ["VerifiableCredential"], + "issuer": {"id": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL"}, + "credentialSubject": { + "id": "did:example:alice", + "name": "Alice", + }, +} + +CREDENTIAL_V2_ISSUED = { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://w3id.org/security/suites/ed25519-2020/v1", + ], + "type": ["VerifiableCredential"], + "issuer": {"id": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL"}, + "credentialSubject": {"id": "did:example:alice", "name": "Alice"}, + "proof": { + "type": "Ed25519Signature2020", + "proofPurpose": "assertionMethod", + "verificationMethod": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL#z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL", + "created": "2025-01-27T21:39:18+00:00", + "proofValue": "zK9VFcysBRqQHQL65WNmKKPbYYrhFabu41SuQXMBGVEHHYLNGrELkNxg2GAxEs6phDZoGNcvhTBhv7fLmJ23U8Hn", + }, +} + +CREDENTIAL_V2_VERIFIED = DocumentVerificationResult( + verified=True, + document={ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://w3id.org/security/suites/ed25519-2020/v1", + ], + "type": ["VerifiableCredential"], + "issuer": {"id": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL"}, + "credentialSubject": {"id": "did:example:alice", "name": "Alice"}, + "proof": { + "type": "Ed25519Signature2020", + "proofPurpose": "assertionMethod", + "verificationMethod": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL#z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL", + "created": "2025-01-27T21:39:18+00:00", + "proofValue": "zK9VFcysBRqQHQL65WNmKKPbYYrhFabu41SuQXMBGVEHHYLNGrELkNxg2GAxEs6phDZoGNcvhTBhv7fLmJ23U8Hn", + }, + }, + results=[ + ProofResult( + verified=True, + proof={ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://w3id.org/security/suites/ed25519-2020/v1", + ], + "type": "Ed25519Signature2020", + "proofPurpose": "assertionMethod", + "verificationMethod": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL#z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL", + "created": "2025-01-27T21:39:18+00:00", + "proofValue": "zK9VFcysBRqQHQL65WNmKKPbYYrhFabu41SuQXMBGVEHHYLNGrELkNxg2GAxEs6phDZoGNcvhTBhv7fLmJ23U8Hn", + }, + purpose_result=PurposeResult( + valid=True, + controller={ + "@context": "https://w3id.org/security/v2", + "id": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL", + "assertionMethod": [ + "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL#z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL" + ], + "authentication": [ + { + "id": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL#z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL", + "type": "Ed25519VerificationKey2018", + "controller": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL", + "publicKeyBase58": "3Dn1SJNPaCXcvvJvSbsFWP2xaCjMom3can8CQNhWrTRx", + } + ], + "capabilityDelegation": [ + "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL#z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL" + ], + "capabilityInvocation": [ + "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL#z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL" + ], + "keyAgreement": [ + { + "id": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL#z6LSbkodSr6SU2trs8VUgnrnWtSm7BAPG245ggrBmSrxbv1R", + "type": "X25519KeyAgreementKey2019", + "controller": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL", + "publicKeyBase58": "5dTvYHaNaB7mk7iA9LqCJEHG2dGZQsvoi8WGzDRtYEf", + } + ], + "verificationMethod": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL#z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL", + }, + ), + ) + ], +) + +PRESENTATION_V2_UNSIGNED = { + "@context": ["https://www.w3.org/ns/credentials/v2"], + "type": ["VerifiablePresentation"], + "holder": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL", + "verifiableCredential": [ + { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://w3id.org/security/suites/ed25519-2020/v1", + ], + "type": ["VerifiableCredential"], + "issuer": {"id": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL"}, + "credentialSubject": {"id": "did:example:alice", "name": "Alice"}, + "proof": { + "type": "Ed25519Signature2020", + "proofPurpose": "assertionMethod", + "verificationMethod": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL#z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL", + "created": "2025-01-27T21:39:18+00:00", + "proofValue": "zK9VFcysBRqQHQL65WNmKKPbYYrhFabu41SuQXMBGVEHHYLNGrELkNxg2GAxEs6phDZoGNcvhTBhv7fLmJ23U8Hn", + }, + } + ], +} + +PRESENTATION_V2_SIGNED = { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://w3id.org/security/suites/ed25519-2020/v1", + ], + "type": ["VerifiablePresentation"], + "holder": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL", + "verifiableCredential": [ + { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://w3id.org/security/suites/ed25519-2020/v1", + ], + "type": ["VerifiableCredential"], + "issuer": {"id": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL"}, + "credentialSubject": {"id": "did:example:alice", "name": "Alice"}, + "proof": { + "type": "Ed25519Signature2020", + "proofPurpose": "assertionMethod", + "verificationMethod": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL#z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL", + "created": "2025-01-27T21:39:18+00:00", + "proofValue": "zK9VFcysBRqQHQL65WNmKKPbYYrhFabu41SuQXMBGVEHHYLNGrELkNxg2GAxEs6phDZoGNcvhTBhv7fLmJ23U8Hn", + }, + } + ], + "proof": { + "type": "Ed25519Signature2020", + "proofPurpose": "authentication", + "verificationMethod": "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL#z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL", + "created": "2025-01-27T21:50:39+00:00", + "challenge": "2b1bbff6-e608-4368-bf84-67471b27e41c", + "proofValue": "z61aNLNSyBVZyYY5xEKYnGDzWbXQhpWa8QXmQMMJpy4zZ71kyxGbRHVwMWdEzU4qwQhLZ7eSfQiX4dENquYGxkbcB", + }, +} diff --git a/acapy_agent/vc/vc_ld/tests/test_vc_v2.py b/acapy_agent/vc/vc_ld/tests/test_vc_v2.py new file mode 100644 index 0000000000..b2d6417499 --- /dev/null +++ b/acapy_agent/vc/vc_ld/tests/test_vc_v2.py @@ -0,0 +1,110 @@ +from datetime import datetime +from unittest import IsolatedAsyncioTestCase, mock + +from ....did.did_key import DIDKey +from ....utils.testing import create_test_profile +from ....wallet.base import BaseWallet +from ....wallet.key_type import ED25519 +from ...ld_proofs import ( + Ed25519Signature2020, + WalletKeyPair, +) +from ...ld_proofs.error import LinkedDataProofException +from ...tests.document_loader import custom_document_loader +from ...vc_ld import ( + sign_presentation, + verify_credential, + verify_presentation, +) +from ...vc_ld import issue_vc as issue +from .test_credential_v2 import ( + CREDENTIAL_V2_ISSUED, + CREDENTIAL_V2_TEMPLATE, + CREDENTIAL_V2_VERIFIED, + PRESENTATION_V2_UNSIGNED, + PRESENTATION_V2_SIGNED, +) + + +class TestLinkedDataVerifiableCredentialV2(IsolatedAsyncioTestCase): + test_seed = "testseed000000000000000000000001" + + async def asyncSetUp(self): + self.profile = await create_test_profile() + async with self.profile.session() as session: + wallet = session.inject(BaseWallet) + self.ed25519_key_info = await wallet.create_signing_key( + key_type=ED25519, seed=self.test_seed + ) + self.ed25519_verification_method = DIDKey.from_public_key_b58( + self.ed25519_key_info.verkey, ED25519 + ).key_id + + self.presentation_challenge = "2b1bbff6-e608-4368-bf84-67471b27e41c" + + async def test_v2_issue_Ed25519Signature2020(self): + suite = Ed25519Signature2020( + verification_method=self.ed25519_verification_method, + key_pair=WalletKeyPair( + profile=self.profile, + key_type=ED25519, + public_key_base58=self.ed25519_key_info.verkey, + ), + date=datetime.strptime( + "2025-01-27T21:39:18+00:00", "%Y-%m-%dT%H:%M:%S+00:00" + ), + ) + + issued = await issue( + credential=CREDENTIAL_V2_TEMPLATE, + suite=suite, + document_loader=custom_document_loader, + ) + assert issued == CREDENTIAL_V2_ISSUED + + async def test_v2_verify_Ed25519Signature2020(self): + # Verification requires lot less input parameters + suite = Ed25519Signature2020( + key_pair=WalletKeyPair(profile=self.profile, key_type=ED25519), + ) + verified = await verify_credential( + credential=CREDENTIAL_V2_ISSUED, + suites=[suite], + document_loader=custom_document_loader, + ) + + assert verified == CREDENTIAL_V2_VERIFIED + + async def test_v2_verify_presentation(self): + suite = Ed25519Signature2020( + key_pair=WalletKeyPair(profile=self.profile, key_type=ED25519), + ) + verification_result = await verify_presentation( + presentation=PRESENTATION_V2_SIGNED, + challenge=self.presentation_challenge, + suites=[suite], + document_loader=custom_document_loader, + ) + + assert verification_result.verified + + async def test_verify_presentation_x_no_purpose_challenge(self): + verification_result = await verify_presentation( + presentation=PRESENTATION_V2_SIGNED, + suites=[], + document_loader=custom_document_loader, + ) + + assert not verification_result.verified + assert 'A "challenge" param is required for AuthenticationProofPurpose' in str( + verification_result.errors[0] + ) + + async def test_sign_presentation_x_no_purpose_challenge(self): + with self.assertRaises(LinkedDataProofException) as context: + await sign_presentation( + presentation=PRESENTATION_V2_UNSIGNED, + suite=mock.MagicMock(), + document_loader=mock.MagicMock(), + ) + assert 'A "challenge" param is required' in str(context.exception) From 6b228d7a81de1ce99cbf35437e8a864e69dd7d06 Mon Sep 17 00:00:00 2001 From: jamshale <31809382+jamshale@users.noreply.github.com> Date: Wed, 26 Feb 2025 10:58:39 -0800 Subject: [PATCH 17/76] Remove base wallet type must be new wallet type restriction (#3542) * Remove base wallet type must be new wallet type restriction Signed-off-by: jamshale * Remove invalid test Signed-off-by: jamshale --------- Signed-off-by: jamshale --- acapy_agent/multitenant/admin/routes.py | 6 --- .../multitenant/admin/tests/test_routes.py | 50 ------------------- acapy_agent/utils/profiles.py | 10 ---- 3 files changed, 66 deletions(-) diff --git a/acapy_agent/multitenant/admin/routes.py b/acapy_agent/multitenant/admin/routes.py index 3d03b6bf62..e0ddee87a1 100644 --- a/acapy_agent/multitenant/admin/routes.py +++ b/acapy_agent/multitenant/admin/routes.py @@ -24,7 +24,6 @@ from ...multitenant.base import BaseMultitenantManager from ...storage.error import StorageError, StorageNotFoundError from ...utils.endorsement_setup import attempt_auto_author_with_endorser_setup -from ...utils.profiles import subwallet_type_not_same_as_base_wallet_raise_web_exception from ...wallet.error import WalletSettingsError from ...wallet.models.wallet_record import WalletRecord, WalletRecordSchema from ..error import WalletKeyMissingError @@ -450,11 +449,6 @@ async def wallet_create(request: web.BaseRequest): base_wallet_type = context.profile.settings.get("wallet.type") sub_wallet_type = body.get("wallet_type", base_wallet_type) - - subwallet_type_not_same_as_base_wallet_raise_web_exception( - base_wallet_type, sub_wallet_type - ) - key_management_mode = body.get("key_management_mode") or WalletRecord.MODE_MANAGED wallet_key = body.get("wallet_key") wallet_webhook_urls = body.get("wallet_webhook_urls") or [] diff --git a/acapy_agent/multitenant/admin/tests/test_routes.py b/acapy_agent/multitenant/admin/tests/test_routes.py index 6f24c863de..44be267d40 100644 --- a/acapy_agent/multitenant/admin/tests/test_routes.py +++ b/acapy_agent/multitenant/admin/tests/test_routes.py @@ -215,56 +215,6 @@ async def test_wallet_create_tenant_settings(self): assert mock_multitenant_mgr.get_wallet_profile.called assert test_module.attempt_auto_author_with_endorser_setup.called - async def test_wallet_create_wallet_type_different_from_base_wallet_raises_403( - self, - ): - body = { - "wallet_name": "test", - "default_label": "test_label", - "wallet_type": "askar", - "wallet_key": "test", - "key_management_mode": "managed", - "wallet_webhook_urls": [], - "wallet_dispatch_type": "base", - } - wallet_mock = mock.MagicMock( - serialize=mock.MagicMock( - return_value={ - "wallet_id": "test", - "settings": {}, - "key_management_mode": body["key_management_mode"], - } - ) - ) - # wallet_record - mock_multitenant_mgr = mock.AsyncMock(BaseMultitenantManager, autospec=True) - mock_multitenant_mgr.create_wallet = mock.CoroutineMock(return_value=wallet_mock) - - mock_multitenant_mgr.create_auth_token = mock.CoroutineMock( - return_value="test_token" - ) - mock_multitenant_mgr.get_wallet_profile = mock.CoroutineMock( - return_value=mock.MagicMock() - ) - self.profile.context.injector.bind_instance( - BaseMultitenantManager, mock_multitenant_mgr - ) - self.request.json = mock.CoroutineMock(return_value=body) - - await test_module.wallet_create(self.request) - - body["wallet_type"] = "askar-anoncreds" - with self.assertRaises(test_module.web.HTTPForbidden): - await test_module.wallet_create(self.request) - - body["wallet_type"] = "indy" - with self.assertRaises(test_module.web.HTTPForbidden): - await test_module.wallet_create(self.request) - - body["wallet_type"] = "in_memory" - with self.assertRaises(test_module.web.HTTPForbidden): - await test_module.wallet_create(self.request) - async def test_wallet_create(self): body = { "wallet_name": "test", diff --git a/acapy_agent/utils/profiles.py b/acapy_agent/utils/profiles.py index 9fd888c3e4..f1afec248d 100644 --- a/acapy_agent/utils/profiles.py +++ b/acapy_agent/utils/profiles.py @@ -25,16 +25,6 @@ def is_not_anoncreds_profile_raise_web_exception(profile: Profile) -> None: raise web.HTTPForbidden(reason=ANONCREDS_PROFILE_REQUIRED_MSG) -def subwallet_type_not_same_as_base_wallet_raise_web_exception( - base_wallet_type: str, sub_wallet_type: str -) -> None: - """Raise a web exception when the subwallet type is not the same as the base wallet type.""" # noqa: E501 - if base_wallet_type != sub_wallet_type: - raise web.HTTPForbidden( - reason="Subwallet type must be the same as the base wallet type" - ) - - async def get_subwallet_profiles_from_storage(root_profile: Profile) -> list[Profile]: """Get subwallet profiles from storage.""" subwallet_profiles = [] From 3057c0ef570d360819624beedbf6dde847dfb2be Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Wed, 26 Feb 2025 14:41:46 -0600 Subject: [PATCH 18/76] fix: connection reuse with multi-tenancy (#3543) Signed-off-by: Daniel Bluhm --- acapy_agent/core/profile.py | 15 +++++++++++++++ acapy_agent/protocols/out_of_band/v1_0/routes.py | 1 + 2 files changed, 16 insertions(+) diff --git a/acapy_agent/core/profile.py b/acapy_agent/core/profile.py index 65e7b4ee76..8c52e419fe 100644 --- a/acapy_agent/core/profile.py +++ b/acapy_agent/core/profile.py @@ -130,6 +130,21 @@ def __repr__(self) -> str: self.__class__.__name__, self.backend, self.name ) + def __eq__(self, other) -> bool: + """Equality checks for profiles. + + Multiple profile instances can exist at the same time but point to the + same profile. This allows us to test equality based on the profile + pointed to by the instance rather than by object reference comparison. + """ + if not isinstance(other, Profile): + return False + + if type(self) is not type(other): + return False + + return self.name == other.name + class ProfileManager(ABC): """Handle provision and open for profile instances.""" diff --git a/acapy_agent/protocols/out_of_band/v1_0/routes.py b/acapy_agent/protocols/out_of_band/v1_0/routes.py index f600e8b808..ced2c6694b 100644 --- a/acapy_agent/protocols/out_of_band/v1_0/routes.py +++ b/acapy_agent/protocols/out_of_band/v1_0/routes.py @@ -328,6 +328,7 @@ async def invitation_receive(request: web.BaseRequest): mediation_id=mediation_id, ) except (DIDXManagerError, StorageError, BaseModelError) as err: + LOGGER.exception("Error during receive invitation") raise web.HTTPBadRequest(reason=err.roll_up) from err return web.json_response(result.serialize()) From a4dec2c754d7414ae7737ac3834326e8045cc505 Mon Sep 17 00:00:00 2001 From: Thiago Romano <112953503+thiagoromanos@users.noreply.github.com> Date: Fri, 28 Feb 2025 13:48:35 -0300 Subject: [PATCH 19/76] fix: tenant access to endpoints leading to access the base wallet (#3545) * Fixing tenant endpoint access --------- Signed-off-by: Thiago Romano --- acapy_agent/admin/decorators/auth.py | 2 +- acapy_agent/admin/tests/test_auth.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/acapy_agent/admin/decorators/auth.py b/acapy_agent/admin/decorators/auth.py index 982a66872b..500850cbcf 100644 --- a/acapy_agent/admin/decorators/auth.py +++ b/acapy_agent/admin/decorators/auth.py @@ -78,7 +78,7 @@ async def tenant_auth(request): (multitenant_enabled and authorization_header) or (not multitenant_enabled and valid_key) or (multitenant_enabled and valid_key and base_wallet_allowed_route) - or insecure_mode + or (insecure_mode and not multitenant_enabled) or request.method == "OPTIONS" ): return await handler(request) diff --git a/acapy_agent/admin/tests/test_auth.py b/acapy_agent/admin/tests/test_auth.py index ee5cdda150..765d7ef213 100644 --- a/acapy_agent/admin/tests/test_auth.py +++ b/acapy_agent/admin/tests/test_auth.py @@ -86,11 +86,11 @@ async def test_options_request(self): await decor_func(self.request) self.decorated_handler.assert_called_once_with(self.request) - async def test_insecure_mode(self): + async def test_insecure_mode_witout_token(self): self.profile.settings["admin.admin_insecure_mode"] = True decor_func = tenant_authentication(self.decorated_handler) - await decor_func(self.request) - self.decorated_handler.assert_called_once_with(self.request) + with self.assertRaises(web.HTTPUnauthorized): + await decor_func(self.request) async def test_single_tenant_invalid_api_key(self): self.profile.settings["multitenant.enabled"] = False From c4cbf661d608068524fa78d0909165696fa3b727 Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Tue, 4 Mar 2025 19:44:38 +0200 Subject: [PATCH 20/76] :arrow_up: Upgrade poetry to 2.1 (#3538) * :arrow_up: Upgrade poetry to 2.1 Signed-off-by: ff137 * :arrow_up: Update lock file to 2.1.1 Signed-off-by: ff137 * :wrench: Configure package-mode = false Signed-off-by: ff137 --------- Signed-off-by: ff137 --- .devcontainer/Dockerfile | 2 +- .devcontainer/devcontainer.json | 2 +- docker/Dockerfile | 2 +- docker/Dockerfile.demo | 2 +- docker/Dockerfile.run | 2 +- docker/Dockerfile.test | 2 +- poetry.lock | 149 +++++++++++++++++++++++++++----- pyproject.toml | 2 +- scenarios/Dockerfile | 2 +- scenarios/pyproject.toml | 1 + 10 files changed, 137 insertions(+), 29 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 911d874d9e..97bd0e4f36 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -2,7 +2,7 @@ ARG VARIANT="3.12" FROM mcr.microsoft.com/devcontainers/python:${VARIANT} -ARG POETRY_VERSION="1.8.3" +ARG POETRY_VERSION="2.1.1" ENV POETRY_HOME="/opt/poetry" \ POETRY_VERSION=${POETRY_VERSION} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index f36fcbf963..311afbdf9b 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -7,7 +7,7 @@ "context": "..", "args": { "VARIANT": "3.12-bookworm", - "POETRY_VERSION": "1.7.1" + "POETRY_VERSION": "2.1.1" } }, "customizations": { diff --git a/docker/Dockerfile b/docker/Dockerfile index 1c4d5e6e37..5f3c99e5cc 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -6,7 +6,7 @@ WORKDIR /src COPY ./acapy_agent ./acapy_agent COPY ./pyproject.toml ./poetry.lock ./README.md ./ -RUN pip install --no-cache-dir poetry==1.8.3 +RUN pip install --no-cache-dir poetry==2.1.1 RUN poetry build FROM python:${python_version}-slim-bookworm AS main diff --git a/docker/Dockerfile.demo b/docker/Dockerfile.demo index 10ca60c06f..2205f42063 100644 --- a/docker/Dockerfile.demo +++ b/docker/Dockerfile.demo @@ -10,7 +10,7 @@ RUN mkdir -p bin && curl -L -o bin/jq \ chmod ug+x bin/jq # Copy and install Aries Agent code -RUN pip install --no-cache-dir poetry==1.8.3 +RUN pip install --no-cache-dir poetry==2.1.1 COPY README.md pyproject.toml poetry.lock ./ diff --git a/docker/Dockerfile.run b/docker/Dockerfile.run index d41de27d19..f7177ded4c 100644 --- a/docker/Dockerfile.run +++ b/docker/Dockerfile.run @@ -12,7 +12,7 @@ WORKDIR /usr/src/app # For consistency with base images, include curl for health checks RUN apt-get update && apt-get install -y curl && apt-get clean -RUN pip install --no-cache-dir poetry==1.8.3 +RUN pip install --no-cache-dir poetry==2.1.1 RUN mkdir -p acapy_agent && touch acapy_agent/__init__.py COPY pyproject.toml poetry.lock README.md ./ diff --git a/docker/Dockerfile.test b/docker/Dockerfile.test index eeb6108ea3..c7cde4a2e4 100644 --- a/docker/Dockerfile.test +++ b/docker/Dockerfile.test @@ -9,7 +9,7 @@ RUN apt-get update -y && \ WORKDIR /usr/src/app -RUN pip install --no-cache-dir poetry==1.8.3 +RUN pip install --no-cache-dir poetry==2.1.1 COPY ./README.md pyproject.toml ./poetry.lock ./ RUN mkdir acapy_agent && touch acapy_agent/__init__.py diff --git a/poetry.lock b/poetry.lock index 0d703ce45d..a3a6a42f03 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -6,6 +6,7 @@ version = "2.4.4" description = "Happy Eyeballs for asyncio" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "aiohappyeyeballs-2.4.4-py3-none-any.whl", hash = "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8"}, {file = "aiohappyeyeballs-2.4.4.tar.gz", hash = "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745"}, @@ -17,6 +18,7 @@ version = "3.11.12" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "aiohttp-3.11.12-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:aa8a8caca81c0a3e765f19c6953416c58e2f4cc1b84829af01dd1c771bb2f91f"}, {file = "aiohttp-3.11.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84ede78acde96ca57f6cf8ccb8a13fbaf569f6011b9a52f870c662d4dc8cd854"}, @@ -111,7 +113,7 @@ propcache = ">=0.2.0" yarl = ">=1.17.0,<2.0" [package.extras] -speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] +speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.2.0) ; sys_platform == \"linux\" or sys_platform == \"darwin\"", "brotlicffi ; platform_python_implementation != \"CPython\""] [[package]] name = "aiohttp-apispec-acapy" @@ -119,6 +121,7 @@ version = "3.0.3" description = "Build and document REST APIs with aiohttp and apispec" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "aiohttp_apispec_acapy-3.0.3-py3-none-any.whl", hash = "sha256:9a5d335c22975da1bbde49ddc04c138ee285d7c38354e88b43babef2eec0bc54"}, {file = "aiohttp_apispec_acapy-3.0.3.tar.gz", hash = "sha256:8cec5f2601f8c2d7d53dd4aebab3975a596d86ea3a1a362eb3b1adadc11662b3"}, @@ -136,6 +139,7 @@ version = "0.7.0" description = "CORS support for aiohttp" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "aiohttp-cors-0.7.0.tar.gz", hash = "sha256:4d39c6d7100fd9764ed1caf8cebf0eb01bf5e3f24e2e073fda6234bc48b19f5d"}, {file = "aiohttp_cors-0.7.0-py3-none-any.whl", hash = "sha256:0451ba59fdf6909d0e2cd21e4c0a43752bc0703d33fc78ae94d9d9321710193e"}, @@ -150,6 +154,7 @@ version = "1.3.2" description = "aiosignal: a list of registered asynchronous callbacks" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"}, {file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"}, @@ -164,6 +169,7 @@ version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, @@ -175,6 +181,7 @@ version = "0.2.0" description = "" optional = false python-versions = ">=3.6.3" +groups = ["main"] files = [ {file = "anoncreds-0.2.0-py3-none-macosx_10_9_universal2.whl", hash = "sha256:ec57e224d5f1b8749c3d6ff75bb61229a4f9c31df1ee863835f025c78ec10cd0"}, {file = "anoncreds-0.2.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:55dd0ad8c8611d2f6af158485dbd2f3c9524694ee4eaf1c5558973f1e436f943"}, @@ -188,6 +195,7 @@ version = "6.8.1" description = "A pluggable API specification generator. Currently supports the OpenAPI Specification (f.k.a. the Swagger specification)." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "apispec-6.8.1-py3-none-any.whl", hash = "sha256:eacba00df745efc9adb2a45cf992300e87938582077e101fb26b78ecf4320beb"}, {file = "apispec-6.8.1.tar.gz", hash = "sha256:f4916cbb7be156963b18f5929a0e42bd2349135834b680a81b12432bcfaa9a39"}, @@ -209,6 +217,7 @@ version = "0.4.3" description = "" optional = false python-versions = ">=3.6.3" +groups = ["main"] files = [ {file = "aries_askar-0.4.3-py3-none-macosx_10_9_universal2.whl", hash = "sha256:fd4073f4abc7bfe423f3a637cb0d2e5fb1b96cfd0e798ee69e26eb5b9528c3e4"}, {file = "aries_askar-0.4.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:a787fdbf343efcdb9f26ce75ed934c2d48378cef08ae5ce69e997cba7c3f1992"}, @@ -222,18 +231,19 @@ version = "24.3.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"}, {file = "attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff"}, ] [package.extras] -benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] +tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] [[package]] name = "base58" @@ -241,6 +251,7 @@ version = "2.1.1" description = "Base58 and Base58Check implementation." optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "base58-2.1.1-py3-none-any.whl", hash = "sha256:11a36f4d3ce51dfc1043f3218591ac4eb1ceb172919cebe05b52a5bcc8d245c2"}, {file = "base58-2.1.1.tar.gz", hash = "sha256:c5d0cb3f5b6e81e8e35da5754388ddcc6d0d14b6c6a132cb93d69ed580a7278c"}, @@ -255,6 +266,7 @@ version = "0.3.0" description = "Python library for general Base-N encodings." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "bases-0.3.0-py3-none-any.whl", hash = "sha256:a2fef3366f3e522ff473d2e95c21523fe8e44251038d5c6150c01481585ebf5b"}, {file = "bases-0.3.0.tar.gz", hash = "sha256:70f04a4a45d63245787f9e89095ca11042685b6b64b542ad916575ba3ccd1570"}, @@ -273,6 +285,7 @@ version = "5.5.1" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "cachetools-5.5.1-py3-none-any.whl", hash = "sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb"}, {file = "cachetools-5.5.1.tar.gz", hash = "sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95"}, @@ -284,6 +297,7 @@ version = "2.0.0" description = "Canonical JSON" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "canonicaljson-2.0.0-py3-none-any.whl", hash = "sha256:c38a315de3b5a0532f1ec1f9153cd3d716abfc565a558d00a4835428a34fca5b"}, {file = "canonicaljson-2.0.0.tar.gz", hash = "sha256:e2fdaef1d7fadc5d9cb59bd3d0d41b064ddda697809ac4325dced721d12f113f"}, @@ -295,6 +309,7 @@ version = "2024.12.14" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, @@ -306,6 +321,7 @@ version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, @@ -385,6 +401,7 @@ version = "3.4.0" description = "Validate configuration and produce human readable error messages." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, @@ -396,6 +413,7 @@ version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, @@ -497,6 +515,8 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "dev"] +markers = "sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -508,6 +528,7 @@ version = "1.7" description = "A drop-in replacement for argparse that allows options to also be set via config files and/or environment variables." optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "ConfigArgParse-1.7-py3-none-any.whl", hash = "sha256:d249da6591465c6c26df64a9f73d2536e743be2f244eb3ebe61114af2f94f86b"}, {file = "ConfigArgParse-1.7.tar.gz", hash = "sha256:e7067471884de5478c58a511e529f0f9bd1c66bfef1dea90935438d6c23306d1"}, @@ -523,6 +544,7 @@ version = "7.6.10" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "coverage-7.6.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78"}, {file = "coverage-7.6.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c"}, @@ -589,7 +611,7 @@ files = [ ] [package.extras] -toml = ["tomli"] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cryptography" @@ -597,6 +619,7 @@ version = "44.0.0" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.7" +groups = ["main"] files = [ {file = "cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092"}, @@ -604,6 +627,7 @@ files = [ {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:60eb32934076fa07e4316b7b2742fa52cbb190b42c2df2863dbc4230a0a9b385"}, {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e"}, {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e"}, {file = "cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053"}, @@ -614,6 +638,7 @@ files = [ {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9abcc2e083cbe8dde89124a47e5e53ec38751f0d7dfd36801008f316a127d7ba"}, {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64"}, {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285"}, {file = "cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417"}, @@ -631,10 +656,10 @@ files = [ cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} [package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0)"] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0) ; python_version >= \"3.8\""] docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] -nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2)"] -pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] +nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_version >= \"3.8\""] +pep8test = ["check-sdist ; python_version >= \"3.8\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] test = ["certifi (>=2024)", "cryptography-vectors (==44.0.0)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] @@ -646,6 +671,8 @@ version = "1.0.1" description = "Cython implementation of Toolz: High performance functional utilities" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "implementation_name == \"cpython\"" files = [ {file = "cytoolz-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cec9af61f71fc3853eb5dca3d42eb07d1f48a4599fa502cbe92adde85f74b042"}, {file = "cytoolz-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:140bbd649dbda01e91add7642149a5987a7c3ccc251f2263de894b89f50b6608"}, @@ -761,6 +788,7 @@ version = "1.8.12" description = "An implementation of the Debug Adapter Protocol for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "debugpy-1.8.12-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:a2ba7ffe58efeae5b8fad1165357edfe01464f9aef25e814e891ec690e7dd82a"}, {file = "debugpy-1.8.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbbd4149c4fc5e7d508ece083e78c17442ee13b0e69bfa6bd63003e486770f45"}, @@ -796,6 +824,7 @@ version = "2.0" description = "A toolset for deeply merging Python dictionaries." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "deepmerge-2.0-py3-none-any.whl", hash = "sha256:6de9ce507115cff0bed95ff0ce9ecc31088ef50cbdf09bc90a09349a318b3d00"}, {file = "deepmerge-2.0.tar.gz", hash = "sha256:5c3d86081fbebd04dd5de03626a0607b809a98fb6ccba5770b62466fe940ff20"}, @@ -810,6 +839,7 @@ version = "0.1.2" description = "An implementation of did:peer:2" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "did_peer_2-0.1.2-py3-none-any.whl", hash = "sha256:d5908cda2d52b7c34428a421044507d7847fd79b78dc8360441c408f4507d612"}, {file = "did_peer_2-0.1.2.tar.gz", hash = "sha256:af8623f62022732e9fadc0289dfb886fd8267767251c4fa0b63694ecd29a7086"}, @@ -824,6 +854,7 @@ version = "0.1.4" description = "An implementation of did:peer:4" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "did_peer_4-0.1.4-py3-none-any.whl", hash = "sha256:4c2bb42a55e4fec08fe008a1585db2f11fe19e36121f8919991add027d7c816f"}, {file = "did_peer_4-0.1.4.tar.gz", hash = "sha256:b367922067b428d33458ca36158eaed40c863cde2fbab6a18a523dccad533c8e"}, @@ -838,6 +869,7 @@ version = "0.3.0" description = "This repository includes Python libraries for working with `did:webvh` (did:web + Verified History) DID documents and the underlying log format." optional = false python-versions = ">= 3.10, <4" +groups = ["main"] files = [] develop = false @@ -860,6 +892,8 @@ version = "0.1.1" description = "DIDComm Messaging implemented with swappable backends." optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"didcommv2\"" files = [ {file = "didcomm_messaging-0.1.1-py3-none-any.whl", hash = "sha256:5350006d3a92e085dd208add738d6439c2b0a950c1fe19011ece71de0574cc1a"}, {file = "didcomm_messaging-0.1.1.tar.gz", hash = "sha256:e3c7c7612b8f9710ccd221b2f5e8456cbf868600f7cc10474fcc98be325702eb"}, @@ -881,6 +915,7 @@ version = "0.3.9" description = "Distribution utilities" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, @@ -892,6 +927,7 @@ version = "0.19.0" description = "ECDSA cryptographic signature library (pure python)" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.6" +groups = ["main"] files = [ {file = "ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a"}, {file = "ecdsa-0.19.0.tar.gz", hash = "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8"}, @@ -910,6 +946,7 @@ version = "0.7.1" description = "eth-hash: The Ethereum hashing function, keccak256, sometimes (erroneously) called sha3" optional = false python-versions = "<4,>=3.8" +groups = ["main"] files = [ {file = "eth_hash-0.7.1-py3-none-any.whl", hash = "sha256:0fb1add2adf99ef28883fd6228eb447ef519ea72933535ad1a0b28c6f65f868a"}, {file = "eth_hash-0.7.1.tar.gz", hash = "sha256:d2411a403a0b0a62e8247b4117932d900ffb4c8c64b15f92620547ca5ce46be5"}, @@ -919,7 +956,7 @@ files = [ dev = ["build (>=0.9.0)", "bump_my_version (>=0.19.0)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel"] docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)"] pycryptodome = ["pycryptodome (>=3.6.6,<4)"] -pysha3 = ["pysha3 (>=1.0.0,<2.0.0)", "safe-pysha3 (>=1.0.0)"] +pysha3 = ["pysha3 (>=1.0.0,<2.0.0) ; python_version < \"3.9\"", "safe-pysha3 (>=1.0.0) ; python_version >= \"3.9\""] test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] @@ -928,6 +965,7 @@ version = "5.1.0" description = "eth-typing: Common type annotations for ethereum python packages" optional = false python-versions = "<4,>=3.8" +groups = ["main"] files = [ {file = "eth_typing-5.1.0-py3-none-any.whl", hash = "sha256:c0d6b93f5385aa84efc4b47ae2bd478da069bc0ffda8b67e0ccb573f43defd29"}, {file = "eth_typing-5.1.0.tar.gz", hash = "sha256:8581f212ee6252aaa285377a77620f6e5f6e16ac3f144c61f098fafd47967b1a"}, @@ -947,6 +985,7 @@ version = "5.2.0" description = "eth-utils: Common utility functions for python code that interacts with Ethereum" optional = false python-versions = "<4,>=3.8" +groups = ["main"] files = [ {file = "eth_utils-5.2.0-py3-none-any.whl", hash = "sha256:4d43eeb6720e89a042ad5b28d4b2111630ae764f444b85cbafb708d7f076da10"}, {file = "eth_utils-5.2.0.tar.gz", hash = "sha256:17e474eb654df6e18f20797b22c6caabb77415a996b3ba0f3cc8df3437463134"}, @@ -969,6 +1008,7 @@ version = "2.1.1" description = "execnet: rapid multi-Python deployment" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"}, {file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"}, @@ -983,6 +1023,7 @@ version = "3.17.0" description = "A platform independent file lock." optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "filelock-3.17.0-py3-none-any.whl", hash = "sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338"}, {file = "filelock-3.17.0.tar.gz", hash = "sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e"}, @@ -991,7 +1032,7 @@ files = [ [package.extras] docs = ["furo (>=2024.8.6)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-asyncio (>=0.25.2)", "pytest-cov (>=6)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.28.1)"] -typing = ["typing-extensions (>=4.12.2)"] +typing = ["typing-extensions (>=4.12.2) ; python_version < \"3.11\""] [[package]] name = "frozendict" @@ -999,6 +1040,7 @@ version = "2.4.6" description = "A simple immutable dictionary" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "frozendict-2.4.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c3a05c0a50cab96b4bb0ea25aa752efbfceed5ccb24c007612bc63e51299336f"}, {file = "frozendict-2.4.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f5b94d5b07c00986f9e37a38dd83c13f5fe3bf3f1ccc8e88edea8fe15d6cd88c"}, @@ -1047,6 +1089,7 @@ version = "1.5.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, @@ -1148,6 +1191,7 @@ version = "2.6.6" description = "File identification library for Python" optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "identify-2.6.6-py2.py3-none-any.whl", hash = "sha256:cbd1810bce79f8b671ecb20f53ee0ae8e86ae84b557de31d89709dc2a48ba881"}, {file = "identify-2.6.6.tar.gz", hash = "sha256:7bec12768ed44ea4761efb47806f0a41f86e7c0a5fdf5950d4648c90eca7e251"}, @@ -1162,6 +1206,7 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -1176,6 +1221,7 @@ version = "1.1.1" description = "" optional = false python-versions = ">=3.6.3" +groups = ["main"] files = [ {file = "indy_credx-1.1.1-py3-none-macosx_10_9_universal2.whl", hash = "sha256:522b90a2362de681e8224b7e5173a9a6093dc48b2ed13599c9eca3df36e29128"}, {file = "indy_credx-1.1.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:05f9a96166f79799c39c62723d78c5480fe9a872dd9dee9fbff1f79d0484c893"}, @@ -1189,6 +1235,7 @@ version = "0.4.2" description = "" optional = false python-versions = ">=3.6.3" +groups = ["main"] files = [ {file = "indy_vdr-0.4.2-py3-none-macosx_10_9_universal2.whl", hash = "sha256:21e4cc22bdb1de581e4abe00e2201d970f46e05d2420437fe023052614867553"}, {file = "indy_vdr-0.4.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:9dc8e16e8a0c4666c1a9f0a3e9967cb3dace92975b8dbb9b0aa2c7785ac5e12b"}, @@ -1202,6 +1249,7 @@ version = "0.5.1" description = "A port of Ruby on Rails inflector to Python" optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"}, {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"}, @@ -1213,6 +1261,7 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -1224,6 +1273,7 @@ version = "3.1.5" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, @@ -1241,6 +1291,7 @@ version = "0.2.3" description = "Typed Python implementation of JSON Canonicalization Scheme as described in RFC 8785. Currently lacks full floating point support" optional = false python-versions = ">=3.8,<4.0" +groups = ["main"] files = [ {file = "jsoncanon-0.2.3-py3-none-any.whl", hash = "sha256:adb35dac2d0c5dd56f1cb374f1ea6f1fff2ebbb4e844b06d9c96b9ccadf12bf0"}, {file = "jsoncanon-0.2.3.tar.gz", hash = "sha256:483c1ef14e6c8151ba69c0bf646551f249698dd523e9c6da1339a688c5f96d6d"}, @@ -1252,10 +1303,9 @@ version = "1.7.0" description = "A final implementation of JSONPath for Python that aims to be standard compliant, including arithmetic and binary comparison operators and providing clear AST for metaprogramming." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c"}, - {file = "jsonpath_ng-1.7.0-py2-none-any.whl", hash = "sha256:898c93fc173f0c336784a3fa63d7434297544b7198124a68f9a3ef9597b0ae6e"}, - {file = "jsonpath_ng-1.7.0-py3-none-any.whl", hash = "sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6"}, ] [package.dependencies] @@ -1267,6 +1317,7 @@ version = "1.5.6" description = "Implementation of JOSE Web standards" optional = false python-versions = ">= 3.8" +groups = ["main"] files = [ {file = "jwcrypto-1.5.6-py3-none-any.whl", hash = "sha256:150d2b0ebbdb8f40b77f543fb44ffd2baeff48788be71f67f03566692fd55789"}, {file = "jwcrypto-1.5.6.tar.gz", hash = "sha256:771a87762a0c081ae6166958a954f80848820b2ab066937dc8b8379d65b1b039"}, @@ -1282,6 +1333,7 @@ version = "5.3.0" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"}, {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"}, @@ -1436,6 +1488,7 @@ version = "3.7" description = "Python implementation of John Gruber's Markdown." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"}, {file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"}, @@ -1451,6 +1504,7 @@ version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, @@ -1521,6 +1575,7 @@ version = "3.26.1" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "marshmallow-3.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c"}, {file = "marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6"}, @@ -1540,6 +1595,7 @@ version = "6.1.0" description = "multidict implementation" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, @@ -1641,6 +1697,7 @@ version = "0.3.1.post4" description = "Python implementation of multiformats protocols." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "multiformats-0.3.1.post4-py3-none-any.whl", hash = "sha256:5b1d61bd8275c9e817bdbee38dbd501b26629011962ee3c86c46e7ccd0b14129"}, {file = "multiformats-0.3.1.post4.tar.gz", hash = "sha256:d00074fdbc7d603c2084b4c38fa17bbc28173cf2750f51f46fbbc5c4d5605fbb"}, @@ -1662,6 +1719,7 @@ version = "0.3.1" description = "Pre-loading configuration module for the 'multiformats' package." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "multiformats-config-0.3.1.tar.gz", hash = "sha256:7eaa80ef5d9c5ee9b86612d21f93a087c4a655cbcb68960457e61adbc62b47a7"}, {file = "multiformats_config-0.3.1-py3-none-any.whl", hash = "sha256:dec4c9d42ed0d9305889b67440f72e8e8d74b82b80abd7219667764b5b0a8e1d"}, @@ -1679,6 +1737,7 @@ version = "1.6.0" description = "Patch asyncio to allow nested event loops" optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, @@ -1690,6 +1749,7 @@ version = "1.9.1" description = "Node.js virtual environment builder" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] files = [ {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, @@ -1701,6 +1761,7 @@ version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, @@ -1712,6 +1773,7 @@ version = "11.1.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "pillow-11.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:e1abe69aca89514737465752b4bcaf8016de61b3be1397a8fc260ba33321b3a8"}, {file = "pillow-11.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c640e5a06869c75994624551f45e5506e4256562ead981cce820d5ab39ae2192"}, @@ -1791,7 +1853,7 @@ docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline fpx = ["olefile"] mic = ["olefile"] tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "trove-classifiers (>=2024.10.12)"] -typing = ["typing-extensions"] +typing = ["typing-extensions ; python_version < \"3.10\""] xmp = ["defusedxml"] [[package]] @@ -1800,6 +1862,7 @@ version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, @@ -1816,6 +1879,7 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -1831,6 +1895,7 @@ version = "3.11" description = "Python Lex & Yacc" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"}, {file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"}, @@ -1842,6 +1907,7 @@ version = "3.1.1" description = "Wraps the portalocker recipe for easy usage" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "portalocker-3.1.1-py3-none-any.whl", hash = "sha256:80e984e24de292ff258a5bea0e4f3f778fff84c0ae1275dbaebc4658de4aacb3"}, {file = "portalocker-3.1.1.tar.gz", hash = "sha256:ec20f6dda2ad9ce89fa399a5f31f4f1495f515958f0cb7ca6543cef7bb5a749e"}, @@ -1861,6 +1927,7 @@ version = "4.1.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b"}, {file = "pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4"}, @@ -1879,6 +1946,7 @@ version = "3.0.50" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.8.0" +groups = ["main"] files = [ {file = "prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198"}, {file = "prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab"}, @@ -1893,6 +1961,7 @@ version = "0.2.1" description = "Accelerated property cache" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6"}, {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2"}, @@ -1984,6 +2053,7 @@ version = "2.22" description = "C parser in Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -1995,6 +2065,7 @@ version = "2.10.5" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"}, {file = "pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff"}, @@ -2007,7 +2078,7 @@ typing-extensions = ">=4.12.2" [package.extras] email = ["email-validator (>=2.0.0)"] -timezone = ["tzdata"] +timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] [[package]] name = "pydantic-core" @@ -2015,6 +2086,7 @@ version = "2.27.2" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, @@ -2127,6 +2199,7 @@ version = "3.3.0" description = "PyDev.Debugger (used in PyDev, PyCharm and VSCode Python)" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "pydevd-3.3.0-cp310-cp310-macosx_14_0_universal2.whl", hash = "sha256:5a3a6948d09db219754efdd254fb462aa68a76e635cabc9cb7e95669ce161b14"}, {file = "pydevd-3.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:04fad1696d596e7bc0e938ca6a08bc0abcc9f6e10099b67148c9fe8abdddf36a"}, @@ -2173,6 +2246,7 @@ version = "251.18673.39" description = "PyCharm Debugger (used in PyCharm and PyDev)" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "pydevd_pycharm-251.18673.39.tar.gz", hash = "sha256:52c3abb328050d6d367688d0999a8cce1d9bca59cddc0a237f955a14907bd68d"}, ] @@ -2183,6 +2257,7 @@ version = "0.5.1" description = "Python library for validating, constructing, and representing DIDs and DID Documents" optional = false python-versions = "<4.0.0,>=3.9.0" +groups = ["main"] files = [ {file = "pydid-0.5.1-py3-none-any.whl", hash = "sha256:be89df79b6267ec1814d49cdd240262c8bbddbfcee9e3aad97a97d521620d6c4"}, {file = "pydid-0.5.1.tar.gz", hash = "sha256:9489a5fbfbecc8dc864c461bb5a0c664895726ab3ca83daf389d91a10146d5e2"}, @@ -2199,6 +2274,7 @@ version = "2.10.1" description = "JSON Web Token implementation in Python" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, @@ -2216,6 +2292,7 @@ version = "2.0.4" description = "Python implementation of the JSON-LD API" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "PyLD-2.0.4-py3-none-any.whl", hash = "sha256:6dab9905644616df33f8755489fc9b354ed7d832d387b7d1974b4fbd3b8d2a89"}, {file = "PyLD-2.0.4.tar.gz", hash = "sha256:311e350f0dbc964311c79c28e86f84e195a81d06fef5a6f6ac2a4f6391ceeacc"}, @@ -2238,6 +2315,7 @@ version = "1.5.0" description = "Python binding to the Networking and Cryptography (NaCl) library" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, @@ -2264,6 +2342,7 @@ version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, @@ -2284,6 +2363,7 @@ version = "0.25.3" description = "Pytest support for asyncio" optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "pytest_asyncio-0.25.3-py3-none-any.whl", hash = "sha256:9e89518e0f9bd08928f97a3482fdc4e244df17529460bc038291ccaf8f85c7c3"}, {file = "pytest_asyncio-0.25.3.tar.gz", hash = "sha256:fc1da2cf9f125ada7e710b4ddad05518d4cee187ae9412e9ac9271003497f07a"}, @@ -2302,6 +2382,7 @@ version = "6.0.0" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"}, {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"}, @@ -2320,6 +2401,7 @@ version = "0.4.1" description = "pytest plugin to check ruff requirements." optional = false python-versions = "<4.0,>=3.8" +groups = ["dev"] files = [ {file = "pytest_ruff-0.4.1-py3-none-any.whl", hash = "sha256:69acd5b2ba68d65998c730b5b4d656788193190e45f61a53aa66ef8b390634a4"}, {file = "pytest_ruff-0.4.1.tar.gz", hash = "sha256:2c9a30f15f384c229c881b52ec86cfaf1e79d39530dd7dd5f2d6aebe278f7eb7"}, @@ -2335,6 +2417,7 @@ version = "3.6.1" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7"}, {file = "pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"}, @@ -2355,6 +2438,7 @@ version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -2369,13 +2453,14 @@ version = "3.2.1" description = "JSON Log Formatter for the Python Logging Package" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "python_json_logger-3.2.1-py3-none-any.whl", hash = "sha256:cdc17047eb5374bd311e748b42f99d71223f3b0e186f4206cc5d52aefe85b090"}, {file = "python_json_logger-3.2.1.tar.gz", hash = "sha256:8eb0554ea17cb75b05d2848bc14fb02fbdbd9d6972120781b974380bfa162008"}, ] [package.extras] -dev = ["backports.zoneinfo", "black", "build", "freezegun", "mdx_truly_sane_lists", "mike", "mkdocs", "mkdocs-awesome-pages-plugin", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-material (>=8.5)", "mkdocstrings[python]", "msgspec", "msgspec-python313-pre", "mypy", "orjson", "pylint", "pytest", "tzdata", "validate-pyproject[all]"] +dev = ["backports.zoneinfo ; python_version < \"3.9\"", "black", "build", "freezegun", "mdx_truly_sane_lists", "mike", "mkdocs", "mkdocs-awesome-pages-plugin", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-material (>=8.5)", "mkdocstrings[python]", "msgspec ; implementation_name != \"pypy\" and python_version < \"3.13\"", "msgspec-python313-pre ; implementation_name != \"pypy\" and python_version == \"3.13\"", "mypy", "orjson ; implementation_name != \"pypy\"", "pylint", "pytest", "tzdata", "validate-pyproject[all]"] [[package]] name = "pywin32" @@ -2383,6 +2468,8 @@ version = "308" description = "Python for Window Extensions" optional = false python-versions = "*" +groups = ["main"] +markers = "platform_system == \"Windows\"" files = [ {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, @@ -2410,6 +2497,7 @@ version = "6.0.2" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, @@ -2472,6 +2560,7 @@ version = "8.0" description = "QR Code image generator" optional = false python-versions = "<4.0,>=3.9" +groups = ["main"] files = [ {file = "qrcode-8.0-py3-none-any.whl", hash = "sha256:9fc05f03305ad27a709eb742cf3097fa19e6f6f93bb9e2f039c0979190f6f1b1"}, {file = "qrcode-8.0.tar.gz", hash = "sha256:025ce2b150f7fe4296d116ee9bad455a6643ab4f6e7dce541613a4758cbce347"}, @@ -2492,6 +2581,7 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -2513,6 +2603,7 @@ version = "4.1.0" description = "rlp: A package for Recursive Length Prefix encoding and decoding" optional = false python-versions = "<4,>=3.8" +groups = ["main"] files = [ {file = "rlp-4.1.0-py3-none-any.whl", hash = "sha256:8eca394c579bad34ee0b937aecb96a57052ff3716e19c7a578883e767bc5da6f"}, {file = "rlp-4.1.0.tar.gz", hash = "sha256:be07564270a96f3e225e2c107db263de96b5bc1f27722d2855bd3459a08e95a9"}, @@ -2533,6 +2624,7 @@ version = "0.9.6" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "ruff-0.9.6-py3-none-linux_armv6l.whl", hash = "sha256:2f218f356dd2d995839f1941322ff021c72a492c470f0b26a34f844c29cdf5ba"}, {file = "ruff-0.9.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b908ff4df65dad7b251c9968a2e4560836d8f5487c2f0cc238321ed951ea0504"}, @@ -2560,6 +2652,7 @@ version = "0.10.4" description = "The reference implementation of the IETF SD-JWT specification." optional = false python-versions = ">=3.8,<4.0" +groups = ["main"] files = [ {file = "sd_jwt-0.10.4-py3-none-any.whl", hash = "sha256:d7ae669eb5d51bceeb38e0df8ab2faddd12e3b21ab64d831b6d048fc1e00ce75"}, {file = "sd_jwt-0.10.4.tar.gz", hash = "sha256:82f93e2f570cfd31fab124e301febb81f3bcad70b10e38f5f9cff70ad659c2ce"}, @@ -2575,6 +2668,7 @@ version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -2586,6 +2680,8 @@ version = "1.0.0" description = "List processing tools and functional utilities" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "implementation_name == \"cpython\" or implementation_name == \"pypy\"" files = [ {file = "toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236"}, {file = "toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02"}, @@ -2597,6 +2693,7 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -2608,6 +2705,7 @@ version = "1.2.11.post4" description = "A simple library for runtime type-checking." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "typing_validation-1.2.11.post4-py3-none-any.whl", hash = "sha256:73dd504ddebf5210e80d5f65ba9b30efbd0fa42f266728fda7c4f0ba335c699c"}, {file = "typing_validation-1.2.11.post4.tar.gz", hash = "sha256:7aed04ecfbda07e63b7266f90e5d096f96344f7facfe04bb081b21e4a9781670"}, @@ -2622,6 +2720,7 @@ version = "0.2.0" description = "Unflatten dict to dict with nested dict/arrays" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "unflatten-0.2.0-py2.py3-none-any.whl", hash = "sha256:a0afa7ff22313dcc60ff45110b796ed5b4e908614826e8672a9f76d3a20c1f54"}, {file = "unflatten-0.2.0.tar.gz", hash = "sha256:9710bc558882f697bc36a95a97614be296f07c8f8df1bc2b4ef96c189ce5cf84"}, @@ -2633,13 +2732,14 @@ version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -2650,6 +2750,8 @@ version = "1.0.1" description = "" optional = true python-versions = ">=3.6.3" +groups = ["main"] +markers = "extra == \"bbs\"" files = [ {file = "ursa_bbs_signatures-1.0.1-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:245701789df0d6cda09faa6194b590c0ce6513b39d80fe8f1fe2a52b69a4b520"}, {file = "ursa_bbs_signatures-1.0.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:79f410a1f89855a4149af7adecaa22a5f427640f5d093f53670657394a9f9ef4"}, @@ -2662,6 +2764,7 @@ version = "0.10.0" description = "Drop-in replacement for Python UUID in Rust" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "uuid_utils-0.10.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8d5a4508feefec62456cd6a41bcdde458d56827d908f226803b886d22a3d5e63"}, {file = "uuid_utils-0.10.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:dbefc2b9113f9dfe56bdae58301a2b3c53792221410d422826f3d1e3e6555fe7"}, @@ -2698,6 +2801,7 @@ version = "20.29.1" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "virtualenv-20.29.1-py3-none-any.whl", hash = "sha256:4e4cb403c0b0da39e13b46b1b2476e505cb0046b25f242bee80f62bf990b2779"}, {file = "virtualenv-20.29.1.tar.gz", hash = "sha256:b8b8970138d32fb606192cb97f6cd4bb644fa486be9308fb9b63f81091b5dc35"}, @@ -2710,7 +2814,7 @@ platformdirs = ">=3.9.1,<5" [package.extras] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] [[package]] name = "wcwidth" @@ -2718,6 +2822,7 @@ version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, @@ -2729,6 +2834,7 @@ version = "8.6.0" description = "Declarative parsing and validation of HTTP request objects, with built-in support for popular web frameworks, including Flask, Django, Bottle, Tornado, Pyramid, Falcon, and aiohttp." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "webargs-8.6.0-py3-none-any.whl", hash = "sha256:83da4d7105643d0a50499b06d98a6ade1a330ce66d039eaa51f715172c704aba"}, {file = "webargs-8.6.0.tar.gz", hash = "sha256:b8d098ab92bd74c659eca705afa31d681475f218cb15c1e57271fa2103c0547a"}, @@ -2750,6 +2856,7 @@ version = "1.18.3" description = "Yet another URL library" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, @@ -2845,6 +2952,6 @@ bbs = ["ursa-bbs-signatures"] didcommv2 = ["didcomm-messaging"] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = "^3.12" content-hash = "1176053f084869dafc9f1754b0eed17985beadc7b99dcbefd8290e86853bac55" diff --git a/pyproject.toml b/pyproject.toml index 8f2e6ae327..4957288d1b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -158,5 +158,5 @@ show_missing = true output = "test-reports/coverage.xml" [build-system] -requires = ["poetry-core"] +requires = ["poetry-core>=2.1"] build-backend = "poetry.core.masonry.api" diff --git a/scenarios/Dockerfile b/scenarios/Dockerfile index d7017c7681..383137450a 100644 --- a/scenarios/Dockerfile +++ b/scenarios/Dockerfile @@ -2,7 +2,7 @@ FROM python:3.10 WORKDIR /usr/src/app/ -ENV POETRY_VERSION=1.8.3 +ENV POETRY_VERSION=2.1.1 ENV POETRY_HOME=/opt/poetry RUN curl --proto "=https" --tlsv1.2 -sSf -L https://install.python-poetry.org | python - diff --git a/scenarios/pyproject.toml b/scenarios/pyproject.toml index b1070e75c7..d9f76270a1 100644 --- a/scenarios/pyproject.toml +++ b/scenarios/pyproject.toml @@ -4,6 +4,7 @@ version = "0.1.0" description = "" authors = [] readme = "README.md" +package-mode = false [tool.poetry.dependencies] python = "^3.10" From d9a6712ccd5a2a5a286d8c5a9e0a46d835f69023 Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Wed, 5 Mar 2025 01:33:20 +0200 Subject: [PATCH 21/76] :bug: Fix: allow multitenant askar-anoncreds wallets to present indy credentials (#3549) * :bug: Remove shim that redirects from indy to anoncreds proof handler The shim prevents an askar-anoncreds wallet from presenting Indy creds. Resolves #3516 Signed-off-by: ff137 * :bug: Load LinkSecret from Anoncreds master secret Signed-off-by: ff137 * :art: Improve logging in get_link_secret Signed-off-by: ff137 * :bug: Attempt standard loading of LinkSecret; use fallback if it fails Signed-off-by: ff137 * :white_check_mark: Test coverage for get_link_secret Signed-off-by: ff137 * :art: Fix type hints Signed-off-by: ff137 --------- Signed-off-by: ff137 --- acapy_agent/askar/profile.py | 8 +- acapy_agent/indy/credx/holder.py | 24 +++- .../indy/credx/tests/test_get_link_secret.py | 130 ++++++++++++++++++ .../v2_0/formats/indy/handler.py | 26 ---- 4 files changed, 159 insertions(+), 29 deletions(-) create mode 100644 acapy_agent/indy/credx/tests/test_get_link_secret.py diff --git a/acapy_agent/askar/profile.py b/acapy_agent/askar/profile.py index e562ff88ff..4afcea0d60 100644 --- a/acapy_agent/askar/profile.py +++ b/acapy_agent/askar/profile.py @@ -178,11 +178,15 @@ def bind_providers(self): ), ) - def session(self, context: Optional[InjectionContext] = None) -> ProfileSession: + def session( + self, context: Optional[InjectionContext] = None + ) -> "AskarProfileSession": """Start a new interactive session with no transaction support requested.""" return AskarProfileSession(self, False, context=context) - def transaction(self, context: Optional[InjectionContext] = None) -> ProfileSession: + def transaction( + self, context: Optional[InjectionContext] = None + ) -> "AskarProfileSession": """Start a new interactive session with commit and rollback support. If the current backend does not support transactions, then commit diff --git a/acapy_agent/indy/credx/holder.py b/acapy_agent/indy/credx/holder.py index 089f1620d1..31d4bb67d3 100644 --- a/acapy_agent/indy/credx/holder.py +++ b/acapy_agent/indy/credx/holder.py @@ -67,6 +67,7 @@ def profile(self) -> AskarProfile: async def get_link_secret(self) -> LinkSecret: """Get or create the default link secret.""" + LOGGER.debug("Attempting to fetch or create the link secret.") while True: async with self._profile.session() as session: @@ -75,30 +76,51 @@ async def get_link_secret(self) -> LinkSecret: CATEGORY_LINK_SECRET, IndyCredxHolder.LINK_SECRET_ID ) except AskarError as err: + LOGGER.error("Error fetching link secret: %s", err) raise IndyHolderError("Error fetching link secret") from err + if record: try: + LOGGER.debug("Loading LinkSecret") secret = LinkSecret.load(record.raw_value) + LOGGER.debug("Loaded existing link secret.") except CredxError as err: - raise IndyHolderError("Error loading link secret") from err + LOGGER.info( + "Attempt fallback method after error loading link secret: %s", + err, + ) + try: + ms_string = record.value.decode("ascii") + link_secret_dict = {"value": {"ms": ms_string}} + secret = LinkSecret.load(link_secret_dict) + LOGGER.debug("Loaded LinkSecret from Anoncreds secret.") + except CredxError as decode_err: + LOGGER.error("Error loading link secret: %s", decode_err) + raise IndyHolderError("Error loading link secret") from err break else: try: secret = LinkSecret.create() + LOGGER.debug("Created new link secret.") except CredxError as err: + LOGGER.error("Error creating link secret: %s", err) raise IndyHolderError("Error creating link secret") from err + try: await session.handle.insert( CATEGORY_LINK_SECRET, IndyCredxHolder.LINK_SECRET_ID, secret.to_json_buffer(), ) + LOGGER.debug("Saved new link secret.") except AskarError as err: if err.code != AskarErrorCode.DUPLICATE: + LOGGER.error("Error saving link secret: %s", err) raise IndyHolderError("Error saving link secret") from err # else: lost race to create record, retry else: break + LOGGER.debug("Returning link secret.") return secret async def create_credential_request( diff --git a/acapy_agent/indy/credx/tests/test_get_link_secret.py b/acapy_agent/indy/credx/tests/test_get_link_secret.py new file mode 100644 index 0000000000..d34a32cbb6 --- /dev/null +++ b/acapy_agent/indy/credx/tests/test_get_link_secret.py @@ -0,0 +1,130 @@ +from unittest import IsolatedAsyncioTestCase + +import pytest +from aries_askar import AskarError, AskarErrorCode + +from acapy_agent.indy.credx.holder import CredxError, IndyHolderError +from acapy_agent.utils.testing import create_test_profile + +from ....tests import mock +from .. import holder + + +@pytest.mark.askar +@pytest.mark.indy_credx +class TestIndyCredxGetLinkSecret(IsolatedAsyncioTestCase): + async def asyncSetUp(self): + self.holder_profile = await create_test_profile() + self.holder = holder.IndyCredxHolder(self.holder_profile) + + self.mock_session = mock.MagicMock() + self.mock_session.__aenter__.return_value = self.mock_session + self.mock_session.__aexit__.return_value = None + self.holder._profile.session = mock.MagicMock(return_value=self.mock_session) + + @mock.patch("acapy_agent.indy.credx.holder.LinkSecret.load") + @mock.patch("acapy_agent.indy.credx.holder.LinkSecret.create") + async def test_get_link_secret_existing(self, mock_create, mock_load): + # Mock session and record + mock_record = mock.MagicMock() + mock_record.raw_value = b'{"value": {"ms": "mocked_ms"}}' + + self.mock_session.handle.fetch = mock.CoroutineMock(return_value=mock_record) + + # Test fetching existing link secret + secret = await self.holder.get_link_secret() + assert secret is not None + mock_load.assert_called_once_with(mock_record.raw_value) + mock_create.assert_not_called() + + @mock.patch("acapy_agent.indy.credx.holder.LinkSecret.load") + async def test_get_link_secret_fetch_error(self, mock_load): + # Mock session to raise an error + self.mock_session.handle.fetch = mock.CoroutineMock( + side_effect=AskarError(AskarErrorCode.BACKEND, "Fetch error") + ) + + with pytest.raises(IndyHolderError, match="Error fetching link secret"): + await self.holder.get_link_secret() + + mock_load.assert_not_called() + + @mock.patch("acapy_agent.indy.credx.holder.LinkSecret.load") + async def test_get_link_secret_load_error(self, mock_load): + # Mock session and record + mock_record = mock.MagicMock() + mock_record.raw_value = b'{"value": {"ms": "mocked_ms"}}' + self.mock_session.handle.fetch = mock.CoroutineMock(return_value=mock_record) + + # Mock load to raise an error + mock_load.side_effect = CredxError(4, "Load error") + + with pytest.raises(IndyHolderError, match="Error loading link secret"): + await self.holder.get_link_secret() + + @mock.patch("acapy_agent.indy.credx.holder.LinkSecret.load") + async def test_get_link_secret_fallback_load(self, mock_load): + # Mock session and record + mock_record = mock.MagicMock() + mock_record.raw_value = b'{"value": {"ms": "mocked_ms"}}' + self.mock_session.handle.fetch = mock.CoroutineMock(return_value=mock_record) + + # Mock load to raise an error initially + mock_load.side_effect = [CredxError(4, "Load error"), mock.MagicMock()] + + # Test fallback method + secret = await self.holder.get_link_secret() + assert secret is not None + assert mock_load.call_count == 2 + + @mock.patch("acapy_agent.indy.credx.holder.LinkSecret.create") + async def test_get_link_secret_create_error(self, mock_create): + # Mock session to return no record + self.mock_session.handle.fetch = mock.CoroutineMock(return_value=None) + + # Mock create to raise an error + mock_create.side_effect = CredxError(4, "Create error") + + with pytest.raises(IndyHolderError, match="Error creating link secret"): + await self.holder.get_link_secret() + + @mock.patch("acapy_agent.indy.credx.holder.LinkSecret.create") + async def test_get_link_secret_create_and_save(self, mock_create): + # Mock session to return no record + self.mock_session.handle.fetch = mock.CoroutineMock(return_value=None) + + # Mock successful creation + mock_secret = mock.MagicMock() + mock_create.return_value = mock_secret + + # Mock successful insert + self.mock_session.handle.insert = mock.CoroutineMock() + + # Test creating and saving new link secret + secret = await self.holder.get_link_secret() + assert secret is not None + mock_create.assert_called_once() + self.mock_session.handle.insert.assert_called_once() + + @mock.patch("acapy_agent.indy.credx.holder.LinkSecret.create") + async def test_get_link_secret_duplicate_error(self, mock_create): + # Mock session to return no record + self.mock_session.handle.fetch = mock.CoroutineMock(return_value=None) + + # Mock successful creation + mock_secret = mock.MagicMock() + mock_create.return_value = mock_secret + + # Mock insert to raise a duplicate error + self.mock_session.handle.insert = mock.CoroutineMock( + side_effect=[ + AskarError(AskarErrorCode.DUPLICATE, "Duplicate error"), + mock.CoroutineMock(), + ] + ) + + # Test handling of duplicate error + secret = await self.holder.get_link_secret() + assert secret is not None + assert mock_create.call_count == 2 + assert self.mock_session.handle.insert.call_count == 2 diff --git a/acapy_agent/protocols/present_proof/v2_0/formats/indy/handler.py b/acapy_agent/protocols/present_proof/v2_0/formats/indy/handler.py index bac3933919..2400b60213 100644 --- a/acapy_agent/protocols/present_proof/v2_0/formats/indy/handler.py +++ b/acapy_agent/protocols/present_proof/v2_0/formats/indy/handler.py @@ -36,17 +36,11 @@ class IndyPresExchangeHandler(V20PresFormatHandler): """Indy presentation format handler.""" format = V20PresFormat.Format.INDY - anoncreds_handler = None def __init__(self, profile: Profile): """Shim initialization to check for new AnonCreds library.""" super().__init__(profile) - # Temporary shim while the new anoncreds library integration is in progress - wallet_type = profile.settings.get_value("wallet.type") - if wallet_type == "askar-anoncreds": - self.anoncreds_handler = AnonCredsPresExchangeHandler(profile) - @classmethod def validate_fields(cls, message_type: str, attachment_data: Mapping): """Validate attachment data for a specific message type. @@ -120,12 +114,6 @@ async def create_bound_request( A tuple (updated presentation exchange record, presentation request message) """ - # Temporary shim while the new anoncreds library integration is in progress - if self.anoncreds_handler: - return await self.anoncreds_handler.create_bound_request( - pres_ex_record, - request_data, - ) indy_proof_request = pres_ex_record.pres_proposal.attachment( IndyPresExchangeHandler.format @@ -149,12 +137,6 @@ async def create_pres( ) -> Tuple[V20PresFormat, AttachDecorator]: """Create a presentation.""" - if self.anoncreds_handler: - return await self.anoncreds_handler.create_pres( - pres_ex_record, - request_data, - ) - requested_credentials = {} if not request_data: try: @@ -323,10 +305,6 @@ def _check_proof_vs_proposal(): f"restrictions {req_restrictions}" ) - # Temporary shim while the new anoncreds library integration is in progress - if self.anoncreds_handler: - return await self.anoncreds_handler.receive_pres(message, pres_ex_record) - proof = message.attachment(IndyPresExchangeHandler.format) _check_proof_vs_proposal() @@ -341,10 +319,6 @@ async def verify_pres(self, pres_ex_record: V20PresExRecord) -> V20PresExRecord: presentation exchange record, updated """ - # Temporary shim while the new anoncreds library integration is in progress - if self.anoncreds_handler: - return await self.anoncreds_handler.verify_pres(pres_ex_record) - pres_request_msg = pres_ex_record.pres_request # The `or` anoncreds format is for the indy <--> anoncreds compatibility From 6bddc8834b473d435a56fbd9b57df24a349e4424 Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Wed, 5 Mar 2025 02:54:11 +0200 Subject: [PATCH 22/76] :bug: Fix: allow anoncreds wallet to delete indy credentials (#3551) * :bug: Fix: allow anoncreds wallet to delete indy credentials Resolves #3550 Signed-off-by: ff137 * :art: Avoid shadowing `profile` Signed-off-by: ff137 * :white_check_mark: Test coverage Signed-off-by: ff137 * :art: Comments Signed-off-by: ff137 --------- Signed-off-by: ff137 Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- acapy_agent/holder/routes.py | 20 ++++++++++++++++---- acapy_agent/holder/tests/test_routes.py | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/acapy_agent/holder/routes.py b/acapy_agent/holder/routes.py index 1fad1fa940..8dfb0f3785 100644 --- a/acapy_agent/holder/routes.py +++ b/acapy_agent/holder/routes.py @@ -351,7 +351,7 @@ async def credentials_remove(request: web.BaseRequest): credential_id = request.match_info["credential_id"] profile: Profile = context.profile - async def delete_credential_using_anoncreds(profile: Profile): + async def delete_credential_using_anoncreds(): try: holder = AnonCredsHolder(profile) await holder.delete_credential(credential_id) @@ -360,7 +360,7 @@ async def delete_credential_using_anoncreds(profile: Profile): raise web.HTTPNotFound(reason=err.roll_up) from err raise web.HTTPBadRequest(reason=err.roll_up) from err - async def delete_credential_using_indy(profile: Profile): + async def delete_credential_using_indy(): async with profile.session() as session: try: holder = session.inject(IndyHolder) @@ -368,10 +368,22 @@ async def delete_credential_using_indy(profile: Profile): except WalletNotFoundError as err: raise web.HTTPNotFound(reason=err.roll_up) from err + async def delete_using_anoncreds_or_indy(): + """Try to delete anoncreds credential with fallback to indy if not found.""" + try: + await delete_credential_using_anoncreds() + except web.HTTPNotFound as anoncreds_err: + # If credential not found in anoncreds, try with indy + try: + await delete_credential_using_indy() + except web.HTTPNotFound: + # Raise original anoncreds error if neither found + raise web.HTTPNotFound(reason=anoncreds_err.reason) from anoncreds_err + if context.settings.get(wallet_type_config) == "askar-anoncreds": - await delete_credential_using_anoncreds(profile) + await delete_using_anoncreds_or_indy() else: - await delete_credential_using_indy(profile) + await delete_credential_using_indy() # Notify event subscribers topic = "acapy::record::credential::delete" diff --git a/acapy_agent/holder/tests/test_routes.py b/acapy_agent/holder/tests/test_routes.py index a91991fac9..615d350244 100644 --- a/acapy_agent/holder/tests/test_routes.py +++ b/acapy_agent/holder/tests/test_routes.py @@ -293,25 +293,43 @@ async def test_credentials_remove_with_anoncreds(self, mock_delete_credential): ) ) + # Anoncreds holder errors mock_delete_credential.side_effect = [ None, AnonCredsHolderError("anoncreds error", error_code=AskarErrorCode.NOT_FOUND), AnonCredsHolderError("anoncreds error", error_code=AskarErrorCode.UNEXPECTED), + AnonCredsHolderError("anoncreds error", error_code=AskarErrorCode.NOT_FOUND), + ] + + # Indy holder errors + mock_indy_holder = mock.MagicMock(IndyHolder, autospec=True) + mock_indy_holder.delete_credential.side_effect = [ + test_module.WalletNotFoundError(), # Indy not found after anoncreds not found + None, # Indy found after second anoncreds not found side effect ] + self.profile.context.injector.bind_instance(IndyHolder, mock_indy_holder) with mock.patch.object( test_module.web, "json_response", mock.Mock() ) as json_response: + # First mock delete has no side effect; delete succeeds result = await test_module.credentials_remove(self.request) json_response.assert_called_once_with({}) assert result is json_response.return_value assert mock_delete_credential.called + # Not found after anoncreds not found and indy not found with self.assertRaises(test_module.web.HTTPNotFound): await test_module.credentials_remove(self.request) + + # Bad request after anoncreds unexpected error with self.assertRaises(test_module.web.HTTPBadRequest): await test_module.credentials_remove(self.request) + # Indy found after anoncreds not found + result = await test_module.credentials_remove(self.request) + assert result is json_response.return_value + async def test_credentials_remove_not_found(self): self.request.match_info = {"credential_id": "dummy"} mock_holder = mock.MagicMock(IndyHolder, autospec=True) From f746e8bd7507bb08dd72596480c3142a33258905 Mon Sep 17 00:00:00 2001 From: Ian Costanzo Date: Wed, 5 Mar 2025 11:01:15 -0800 Subject: [PATCH 23/76] Fix prompt for alice/faber demo (#3553) Signed-off-by: Ian Costanzo --- demo/runners/support/utils.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/demo/runners/support/utils.py b/demo/runners/support/utils.py index 609528da4c..ebd8c9e67b 100644 --- a/demo/runners/support/utils.py +++ b/demo/runners/support/utils.py @@ -7,6 +7,7 @@ import prompt_toolkit import pygments from prompt_toolkit.application import run_in_terminal +from prompt_toolkit.eventloop.defaults import use_asyncio_event_loop from prompt_toolkit.formatted_text import FormattedText, PygmentsTokens from prompt_toolkit.patch_stdout import patch_stdout from prompt_toolkit.shortcuts import ProgressBar @@ -141,7 +142,15 @@ def flatten(args): yield arg +def prompt_init(): + if hasattr(prompt_init, "_called"): + return + prompt_init._called = True + use_asyncio_event_loop() + + async def prompt(*args, **kwargs): + prompt_init() with patch_stdout(): try: while True: From 630563d8135c4a3615681e8db051a14a78785e97 Mon Sep 17 00:00:00 2001 From: jamshale <31809382+jamshale@users.noreply.github.com> Date: Thu, 6 Mar 2025 09:18:31 -0800 Subject: [PATCH 24/76] Fix revocation accum sync when endorsement txn fails (#3547) Refactor cognitive complexity Add happy path unit test Raise a responder None error Remove unused duplicated funtion Signed-off-by: jamshale --- .../endorsed_transaction_response_handler.py | 7 +- acapy_agent/revocation/manager.py | 155 +++++++++++++++++- acapy_agent/revocation/routes.py | 10 ++ acapy_agent/revocation/tests/test_manager.py | 99 +++++++++++ acapy_agent/revocation/util.py | 9 + 5 files changed, 277 insertions(+), 3 deletions(-) diff --git a/acapy_agent/protocols/endorse_transaction/v1_0/handlers/endorsed_transaction_response_handler.py b/acapy_agent/protocols/endorse_transaction/v1_0/handlers/endorsed_transaction_response_handler.py index 644d860571..923c65d8ba 100644 --- a/acapy_agent/protocols/endorse_transaction/v1_0/handlers/endorsed_transaction_response_handler.py +++ b/acapy_agent/protocols/endorse_transaction/v1_0/handlers/endorsed_transaction_response_handler.py @@ -6,6 +6,7 @@ HandlerException, RequestContext, ) +from .....revocation.util import notify_rev_reg_entry_txn_failed from .....storage.error import StorageError from ..manager import TransactionManager, TransactionManagerError from ..messages.endorsed_transaction_response import EndorsedTransactionResponse @@ -30,12 +31,15 @@ async def handle(self, context: RequestContext, responder: BaseResponder): if not context.connection_ready: raise HandlerException("No connection established") - # profile_session = await context.session() + async def send_failed_transaction_event(err_msg: str): + await notify_rev_reg_entry_txn_failed(context.profile, err_msg) + mgr = TransactionManager(context.profile) try: transaction = await mgr.receive_endorse_response(context.message) except TransactionManagerError as err: self._logger.exception("Error receiving endorsed transaction response") + await send_failed_transaction_event(str(err)) raise HandlerException(str(err)) # Automatically write transaction if flag is set @@ -52,4 +56,5 @@ async def handle(self, context: RequestContext, responder: BaseResponder): ) except (StorageError, TransactionManagerError) as err: self._logger.exception(err) + await send_failed_transaction_event(str(err)) raise HandlerException(str(err)) diff --git a/acapy_agent/revocation/manager.py b/acapy_agent/revocation/manager.py index 880c51e840..be5de7cd1d 100644 --- a/acapy_agent/revocation/manager.py +++ b/acapy_agent/revocation/manager.py @@ -1,13 +1,25 @@ """Classes to manage credential revocation.""" +import asyncio import json import logging from typing import Mapping, NamedTuple, Optional, Sequence, Text, Tuple +from ..cache.base import BaseCache from ..connections.models.conn_record import ConnRecord from ..core.error import BaseError -from ..core.profile import Profile +from ..core.profile import Profile, ProfileSession +from ..indy.credx.issuer import CATEGORY_REV_REG from ..indy.issuer import IndyIssuer +from ..ledger.base import BaseLedger +from ..messaging.responder import BaseResponder +from ..protocols.endorse_transaction.v1_0.manager import ( + TransactionManager, + TransactionManagerError, +) +from ..protocols.endorse_transaction.v1_0.util import ( + get_endorser_connection_id, +) from ..protocols.issue_credential.v1_0.models.credential_exchange import ( V10CredentialExchange, ) @@ -15,12 +27,14 @@ from ..protocols.revocation_notification.v1_0.models.rev_notification_record import ( RevNotificationRecord, ) -from ..storage.error import StorageNotFoundError +from ..storage.error import StorageError, StorageNotFoundError from .indy import IndyRevocation from .models.issuer_cred_rev_record import IssuerCredRevRecord from .models.issuer_rev_reg_record import IssuerRevRegRecord from .util import notify_pending_cleared_event, notify_revocation_published_event +LOGGER = logging.getLogger(__name__) + class RevocationManagerError(BaseError): """Revocation manager error.""" @@ -498,3 +512,140 @@ async def set_cred_revoked_state( await txn.commit() except StorageNotFoundError: pass + + async def _get_endorser_info(self) -> Tuple[Optional[str], Optional[ConnRecord]]: + connection_id = await get_endorser_connection_id(self._profile) + + endorser_did = None + async with self._profile.session() as session: + connection_record = await ConnRecord.retrieve_by_id(session, connection_id) + endorser_info = await connection_record.metadata_get(session, "endorser_info") + endorser_did = endorser_info.get("endorser_did") + + return endorser_did, connection_record + + async def fix_and_publish_from_invalid_accum_err(self, err_msg: str): + """Fix and publish revocation registry entries from invalid accumulator error.""" + cache = self._profile.inject_or(BaseCache) + + async def check_retry(accum): + """Used to manage retries for fixing revocation registry entries.""" + retry_value = await cache.get(accum) + if not retry_value: + await cache.set(accum, 5) + else: + if retry_value > 0: + await cache.set(accum, retry_value - 1) + else: + LOGGER.error( + f"Revocation registry entry transaction failed for {accum}" + ) + + def get_genesis_transactions(): + """Get the genesis transactions needed for fixing broken accum.""" + genesis_transactions = self._profile.context.settings.get( + "ledger.genesis_transactions" + ) + if not genesis_transactions: + write_ledger = self._profile.context.injector.inject(BaseLedger) + pool = write_ledger.pool + genesis_transactions = pool.genesis_txns + return genesis_transactions + + async def sync_accumulator(session: ProfileSession): + """Sync the local accumulator with the ledger and create recovery txn.""" + rev_reg_record = await IssuerRevRegRecord.retrieve_by_id( + session, rev_reg_entry.name + ) + + # Fix and get the recovery transaction + ( + rev_reg_delta, + recovery_txn, + applied_txn, + ) = await rev_reg_record.fix_ledger_entry( + self._profile, False, genesis_transactions + ) + + # Update locally assuming ledger write will succeed + rev_reg = await session.handle.fetch( + CATEGORY_REV_REG, + rev_reg_entry.value_json["revoc_reg_id"], + for_update=True, + ) + new_value_json = rev_reg.value_json + new_value_json["value"]["accum"] = recovery_txn["value"]["accum"] + await session.handle.replace( + CATEGORY_REV_REG, + rev_reg.name, + json.dumps(new_value_json), + rev_reg.tags, + ) + + return rev_reg_record, recovery_txn + + async def create_and_send_endorser_txn(): + """Create and send the endorser transaction again.""" + async with ledger: + # Create the revocation registry entry + rev_entry_res = await ledger.send_revoc_reg_entry( + rev_reg_entry.value_json["revoc_reg_id"], + "CL_ACCUM", + recovery_txn, + rev_reg_record.issuer_did, + write_ledger=False, + endorser_did=endorser_did, + ) + + # Send the transaction to the endorser again with recovery txn + transaction_manager = TransactionManager(self._profile) + try: + revo_transaction = await transaction_manager.create_record( + messages_attach=rev_entry_res["result"], + connection_id=connection.connection_id, + ) + ( + revo_transaction, + revo_transaction_request, + ) = await transaction_manager.create_request(transaction=revo_transaction) + except (StorageError, TransactionManagerError) as err: + raise RevocationManagerError(err.roll_up) from err + + responder = self._profile.inject_or(BaseResponder) + if not responder: + raise RevocationManagerError( + "No responder found. Unable to send transaction request" + ) + await responder.send( + revo_transaction_request, + connection_id=connection.connection_id, + ) + + async with self._profile.session() as session: + rev_reg_records = await session.handle.fetch_all( + IssuerRevRegRecord.RECORD_TYPE + ) + # Cycle through all rev_rev_def records to find the offending accumulator + for rev_reg_entry in rev_reg_records: + ledger = session.inject_or(BaseLedger) + # Get the value from the ledger + async with ledger: + (accum_response, _) = await ledger.get_revoc_reg_delta( + rev_reg_entry.value_json["revoc_reg_id"] + ) + accum = accum_response.get("value", {}).get("accum") + + # If the accum from the ledger matches the error message, fix it + if accum and accum in err_msg: + await check_retry(accum) + + # Get the genesis transactions needed for fix + genesis_transactions = get_genesis_transactions() + + # We know this needs endorsement + endorser_did, connection = await self._get_endorser_info() + rev_reg_record, recovery_txn = await sync_accumulator(session=session) + await create_and_send_endorser_txn() + + # Some time in between re-tries + await asyncio.sleep(1) diff --git a/acapy_agent/revocation/routes.py b/acapy_agent/revocation/routes.py index 4899e729a8..6f1427861e 100644 --- a/acapy_agent/revocation/routes.py +++ b/acapy_agent/revocation/routes.py @@ -1557,6 +1557,10 @@ def register_events(event_bus: EventBus): re.compile(f"^{REVOCATION_EVENT_PREFIX}{REVOCATION_ENTRY_EVENT}.*"), on_revocation_entry_event, ) + event_bus.subscribe( + re.compile(f"^{REVOCATION_EVENT_PREFIX}REV_REG_ENTRY_TXN_FAILED.*"), + on_rev_reg_entry_txn_failed, + ) async def on_revocation_registry_init_event(profile: Profile, event: Event): @@ -1747,6 +1751,12 @@ async def on_revocation_registry_endorsed_event(profile: Profile, event: Event): ) +async def on_rev_reg_entry_txn_failed(profile: Profile, event: Event): + """Handle revocation registry entry transaction failed event.""" + manager = RevocationManager(profile) + await manager.fix_and_publish_from_invalid_accum_err(event.payload.get("msg")) + + class TailsDeleteResponseSchema(OpenAPISchema): """Return schema for tails deletion.""" diff --git a/acapy_agent/revocation/tests/test_manager.py b/acapy_agent/revocation/tests/test_manager.py index 3105141cb8..2334724614 100644 --- a/acapy_agent/revocation/tests/test_manager.py +++ b/acapy_agent/revocation/tests/test_manager.py @@ -1,8 +1,15 @@ import json from unittest import IsolatedAsyncioTestCase +from uuid_utils import uuid4 + +from ...cache.base import BaseCache +from ...cache.in_memory import InMemoryCache from ...connections.models.conn_record import ConnRecord +from ...indy.credx.issuer import CATEGORY_REV_REG from ...indy.issuer import IndyIssuer +from ...ledger.base import BaseLedger +from ...messaging.responder import BaseResponder from ...protocols.issue_credential.v1_0.models.credential_exchange import ( V10CredentialExchange, ) @@ -14,6 +21,7 @@ from ...utils.testing import create_test_profile from .. import manager as test_module from ..manager import RevocationManager, RevocationManagerError +from ..models.issuer_rev_reg_record import IssuerRevRegRecord TEST_DID = "LjgpST2rjsoxYegQDRm7EL" SCHEMA_NAME = "bc-reg" @@ -889,3 +897,94 @@ async def test_set_revoked_state_v2(self): session, crev_record.record_id ) assert check_crev_record.state == IssuerCredRevRecord.STATE_REVOKED + + @mock.patch.object( + ConnRecord, + "retrieve_by_id", + mock.CoroutineMock( + return_value=mock.MagicMock( + connection_id="endorser-id", + metadata_get=mock.CoroutineMock( + return_value={"endorser_did": "test_endorser_did"} + ), + ) + ), + ) + @mock.patch.object( + IssuerRevRegRecord, + "fix_ledger_entry", + mock.CoroutineMock( + return_value=( + "1 ...", + { + "ver": "1.0", + "value": { + "prevAccum": "1 ...", + "accum": "fixed-accum", + "issued": [1], + }, + }, + [1], + ) + ), + ) + async def test_fix_and_publish_from_invalid_accum_err( + self, + ): + # Setup + self.profile.context.injector.bind_instance(BaseCache, InMemoryCache()) + self.profile.context.injector.bind_instance( + BaseResponder, mock.MagicMock(BaseResponder, autospec=True) + ) + mock_ledger = mock.MagicMock(BaseLedger, autospec=True) + mock_ledger.get_revoc_reg_delta = mock.CoroutineMock( + side_effect=[ + ({"value": {"accum": "other-accum"}}, None), + ({"value": {"accum": "invalid-accum"}}, None), + ] + ) + mock_ledger.send_revoc_reg_entry = mock.CoroutineMock( + return_value={"result": {"txn": "..."}} + ) + self.profile.context.injector.bind_instance(BaseLedger, mock_ledger) + self.profile.context.settings.set_value( + "ledger.genesis_transactions", {"txn": "..."} + ) + self.profile.context.settings.set_value("endorser.endorser_alias", "endorser") + + async with self.profile.session() as session: + # Add an endorser connection + await session.handle.insert( + ConnRecord.RECORD_TYPE, + name="endorser", + value_json={"connection_id": "endorser", "alias": "endorser"}, + ) + record = ConnRecord( + alias="endorser", + ) + await record.save(session) + + # Add a couple rev reg records + for _ in range(2): + await session.handle.insert( + IssuerRevRegRecord.RECORD_TYPE, + name=str(uuid4()), + value_json={ + "revoc_reg_id": "test-rr-id", + }, + ) + + # Need a matching revocation_reg record + await session.handle.insert( + CATEGORY_REV_REG, + name="test-rr-id", + value_json={ + "value": { + "accum": "invalid-accum", + "revoked": [1], + } + }, + ) + + # Execute + await self.manager.fix_and_publish_from_invalid_accum_err("invalid-accum") diff --git a/acapy_agent/revocation/util.py b/acapy_agent/revocation/util.py index 62853d267a..33ca82b2ba 100644 --- a/acapy_agent/revocation/util.py +++ b/acapy_agent/revocation/util.py @@ -76,3 +76,12 @@ async def notify_pending_cleared_event( """Send notification of credential revoked as issuer.""" topic = f"{REVOCATION_EVENT_PREFIX}{REVOCATION_CLEAR_PENDING_EVENT}::{rev_reg_id}" await profile.notify(topic, {"rev_reg_id": rev_reg_id}) + + +async def notify_rev_reg_entry_txn_failed( + profile: Profile, + msg: str, +): + """Send notification that a revocation registry entry transaction failed.""" + topic = f"{REVOCATION_EVENT_PREFIX}REV_REG_ENTRY_TXN_FAILED" + await profile.notify(topic, {"msg": msg}) From 62dddf6f4eb97dfc6db944bbe32a28b4a2af851e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 20:32:53 +0000 Subject: [PATCH 25/76] chore(deps): Bump dawidd6/action-download-artifact (#3548) Bumps the all-actions group with 1 update: [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact). Updates `dawidd6/action-download-artifact` from 8 to 9 - [Release notes](https://github.com/dawidd6/action-download-artifact/releases) - [Commits](https://github.com/dawidd6/action-download-artifact/compare/v8...v9) --- updated-dependencies: - dependency-name: dawidd6/action-download-artifact dependency-type: direct:production update-type: version-update:semver-major dependency-group: all-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- .github/workflows/sonar-pr.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sonar-pr.yml b/.github/workflows/sonar-pr.yml index d1052aaf53..2d83291bce 100644 --- a/.github/workflows/sonar-pr.yml +++ b/.github/workflows/sonar-pr.yml @@ -15,7 +15,7 @@ jobs: with: fetch-depth: 0 - name: Download PR number artifact - uses: dawidd6/action-download-artifact@v8 + uses: dawidd6/action-download-artifact@v9 with: workflow: Tests run_id: ${{ github.event.workflow_run.id }} @@ -26,7 +26,7 @@ jobs: with: path: ./PR_NUMBER - name: Download Test Coverage - uses: dawidd6/action-download-artifact@v8 + uses: dawidd6/action-download-artifact@v9 with: workflow: Tests run_id: ${{ github.event.workflow_run.id }} From 0e34e11026c89bbade0d000e4188e3cbeb1e51e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 20:39:07 +0000 Subject: [PATCH 26/76] chore(deps): Bump python-json-logger from 3.2.1 to 3.3.0 (#3566) Bumps [python-json-logger](https://github.com/nhairs/python-json-logger) from 3.2.1 to 3.3.0. - [Release notes](https://github.com/nhairs/python-json-logger/releases) - [Changelog](https://github.com/nhairs/python-json-logger/blob/main/docs/changelog.md) - [Commits](https://github.com/nhairs/python-json-logger/compare/v3.2.1...v3.3.0) --- updated-dependencies: - dependency-name: python-json-logger dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- poetry.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index a3a6a42f03..9b33e5b265 100644 --- a/poetry.lock +++ b/poetry.lock @@ -627,7 +627,6 @@ files = [ {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543"}, - {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:60eb32934076fa07e4316b7b2742fa52cbb190b42c2df2863dbc4230a0a9b385"}, {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e"}, {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e"}, {file = "cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053"}, @@ -638,7 +637,6 @@ files = [ {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c"}, - {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9abcc2e083cbe8dde89124a47e5e53ec38751f0d7dfd36801008f316a127d7ba"}, {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64"}, {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285"}, {file = "cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417"}, @@ -1306,6 +1304,8 @@ python-versions = "*" groups = ["main"] files = [ {file = "jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c"}, + {file = "jsonpath_ng-1.7.0-py2-none-any.whl", hash = "sha256:898c93fc173f0c336784a3fa63d7434297544b7198124a68f9a3ef9597b0ae6e"}, + {file = "jsonpath_ng-1.7.0-py3-none-any.whl", hash = "sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6"}, ] [package.dependencies] @@ -2449,18 +2449,18 @@ six = ">=1.5" [[package]] name = "python-json-logger" -version = "3.2.1" +version = "3.3.0" description = "JSON Log Formatter for the Python Logging Package" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "python_json_logger-3.2.1-py3-none-any.whl", hash = "sha256:cdc17047eb5374bd311e748b42f99d71223f3b0e186f4206cc5d52aefe85b090"}, - {file = "python_json_logger-3.2.1.tar.gz", hash = "sha256:8eb0554ea17cb75b05d2848bc14fb02fbdbd9d6972120781b974380bfa162008"}, + {file = "python_json_logger-3.3.0-py3-none-any.whl", hash = "sha256:dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7"}, + {file = "python_json_logger-3.3.0.tar.gz", hash = "sha256:12b7e74b17775e7d565129296105bbe3910842d9d0eb083fc83a6a617aa8df84"}, ] [package.extras] -dev = ["backports.zoneinfo ; python_version < \"3.9\"", "black", "build", "freezegun", "mdx_truly_sane_lists", "mike", "mkdocs", "mkdocs-awesome-pages-plugin", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-material (>=8.5)", "mkdocstrings[python]", "msgspec ; implementation_name != \"pypy\" and python_version < \"3.13\"", "msgspec-python313-pre ; implementation_name != \"pypy\" and python_version == \"3.13\"", "mypy", "orjson ; implementation_name != \"pypy\"", "pylint", "pytest", "tzdata", "validate-pyproject[all]"] +dev = ["backports.zoneinfo ; python_version < \"3.9\"", "black", "build", "freezegun", "mdx_truly_sane_lists", "mike", "mkdocs", "mkdocs-awesome-pages-plugin", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-material (>=8.5)", "mkdocstrings[python]", "msgspec ; implementation_name != \"pypy\"", "mypy", "orjson ; implementation_name != \"pypy\"", "pylint", "pytest", "tzdata", "validate-pyproject[all]"] [[package]] name = "pywin32" From e6ac0f7b852ba5d3d7b65fcf657a68ecf7b029f0 Mon Sep 17 00:00:00 2001 From: jamshale <31809382+jamshale@users.noreply.github.com> Date: Mon, 10 Mar 2025 15:08:25 -0700 Subject: [PATCH 27/76] Update acapy images to 1.2.3 (#3571) Signed-off-by: jamshale --- demo/docker-agent/Dockerfile.acapy | 2 +- demo/multi-demo/Dockerfile.acapy | 2 +- demo/playground/Dockerfile.acapy | 2 +- demo/playground/README.md | 2 +- docker/Dockerfile.demo | 2 +- docs/features/DIDResolution.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/demo/docker-agent/Dockerfile.acapy b/demo/docker-agent/Dockerfile.acapy index 7a4c35f3d5..20e574fa3d 100644 --- a/demo/docker-agent/Dockerfile.acapy +++ b/demo/docker-agent/Dockerfile.acapy @@ -1,4 +1,4 @@ -FROM ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.2 +FROM ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.3 USER root diff --git a/demo/multi-demo/Dockerfile.acapy b/demo/multi-demo/Dockerfile.acapy index 7a4c35f3d5..20e574fa3d 100644 --- a/demo/multi-demo/Dockerfile.acapy +++ b/demo/multi-demo/Dockerfile.acapy @@ -1,4 +1,4 @@ -FROM ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.2 +FROM ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.3 USER root diff --git a/demo/playground/Dockerfile.acapy b/demo/playground/Dockerfile.acapy index 6c0e56205d..b427677064 100644 --- a/demo/playground/Dockerfile.acapy +++ b/demo/playground/Dockerfile.acapy @@ -1,4 +1,4 @@ -FROM ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.2 +FROM ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.3 USER root diff --git a/demo/playground/README.md b/demo/playground/README.md index 19ed6d8b4d..534f50eb15 100644 --- a/demo/playground/README.md +++ b/demo/playground/README.md @@ -26,7 +26,7 @@ These configuration files are provided to the ACA-Py start command via the `AGEN ### Dockerfile and start.sh -[`Dockerfile.acapy`](./Dockerfile.acapy) assembles the image to run. Currently based on [ACA-Py 1.2.0](ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.2), we need [jq](https://stedolan.github.io/jq/) to setup (or not) the ngrok tunnel and execute the Aca-py start command - see [`start.sh`](./start.sh). You may note that the start command is very sparse, additional configuration is done via environment variables in the [docker compose file](./docker-compose.yml). +[`Dockerfile.acapy`](./Dockerfile.acapy) assembles the image to run. Currently based on [ACA-Py 1.2.0](ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.3), we need [jq](https://stedolan.github.io/jq/) to setup (or not) the ngrok tunnel and execute the Aca-py start command - see [`start.sh`](./start.sh). You may note that the start command is very sparse, additional configuration is done via environment variables in the [docker compose file](./docker-compose.yml). ### ngrok diff --git a/docker/Dockerfile.demo b/docker/Dockerfile.demo index 2205f42063..e4e9991ab7 100644 --- a/docker/Dockerfile.demo +++ b/docker/Dockerfile.demo @@ -1,4 +1,4 @@ -ARG from_image=ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.2 +ARG from_image=ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.3 FROM ${from_image} ENV ENABLE_PTVSD 0 diff --git a/docs/features/DIDResolution.md b/docs/features/DIDResolution.md index 224bf1d515..f67e396e88 100644 --- a/docs/features/DIDResolution.md +++ b/docs/features/DIDResolution.md @@ -176,7 +176,7 @@ plugin: The following is a fully functional Dockerfile encapsulating this setup: ```dockerfile= -FROM ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.2 +FROM ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.3 RUN pip3 install git+https://github.com/dbluhm/acapy-resolver-github CMD ["aca-py", "start", "-it", "http", "0.0.0.0", "3000", "-ot", "http", "-e", "http://localhost:3000", "--admin", "0.0.0.0", "3001", "--admin-insecure-mode", "--no-ledger", "--plugin", "acapy_resolver_github"] From 8a642ffc2ba95feca2bd2cda1aa6bea6c3ad46a2 Mon Sep 17 00:00:00 2001 From: Parth Patel <60785604+parth5805@users.noreply.github.com> Date: Tue, 11 Mar 2025 20:45:37 +0530 Subject: [PATCH 28/76] Fix missing log_timer import in acme.py (#3562) The script runners/acme.py was missing an import for log_timer, which caused an error during execution. This function was not mentioned in AcmeDemoWorkshop.md, but was required for proper functionality. Changes: - Added log_timer to the import list in runners/acme.py. This ensures that the script runs without import-related errors. Signed-off-by: Parth Patel <60785604+parth5805@users.noreply.github.com> Co-authored-by: Ian Costanzo --- demo/runners/acme.py | 1 + 1 file changed, 1 insertion(+) diff --git a/demo/runners/acme.py b/demo/runners/acme.py index 61208ba8be..cb17342675 100644 --- a/demo/runners/acme.py +++ b/demo/runners/acme.py @@ -14,6 +14,7 @@ check_requires, log_msg, log_status, + log_timer, prompt, prompt_loop, ) From 093d206253174f202293518b253e369a827f0fd2 Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Tue, 11 Mar 2025 21:06:52 +0200 Subject: [PATCH 29/76] :zap: Use pytest-xdist to run tests in parallel (#3574) Signed-off-by: ff137 Co-authored-by: Stephen Curran --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 4957288d1b..91be2f7193 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -126,6 +126,7 @@ line-length = 90 [tool.pytest.ini_options] testpaths = "acapy_agent" addopts = """ + -n auto --quiet --junitxml=./test-reports/junit.xml --cov-config .coveragerc --cov-report term --cov-report xml --ruff From a7f2d419cb2c0771541e8a50a3ccc541d13a8449 Mon Sep 17 00:00:00 2001 From: jamshale <31809382+jamshale@users.noreply.github.com> Date: Tue, 11 Mar 2025 15:35:26 -0700 Subject: [PATCH 30/76] Repair anoncreds holder revocation list request (#3570) --- acapy_agent/anoncreds/holder.py | 16 +- .../anoncreds/pres_exch_handler.py | 3 +- demo/runners/faber.py | 5 +- .../example.py | 158 +++++++++++++++--- scenarios/examples/util.py | 10 ++ 5 files changed, 159 insertions(+), 33 deletions(-) diff --git a/acapy_agent/anoncreds/holder.py b/acapy_agent/anoncreds/holder.py index 11f47fea78..e6cbedf37c 100644 --- a/acapy_agent/anoncreds/holder.py +++ b/acapy_agent/anoncreds/holder.py @@ -1,4 +1,4 @@ -"""Indy holder implementation.""" +"""Anoncreds holder implementation.""" import asyncio import json @@ -598,10 +598,10 @@ async def create_presentation( Args: presentation_request: Valid indy format presentation request - requested_credentials: Indy format requested credentials - schemas: Indy formatted schemas JSON - credential_definitions: Indy formatted credential definitions JSON - rev_states: Indy format revocation states JSON + requested_credentials: Anoncreds format requested credentials + schemas: Anoncreds formatted schemas JSON + credential_definitions: Anoncreds formatted credential definitions JSON + rev_states: Anoncreds format revocation states JSON """ @@ -691,9 +691,9 @@ async def create_presentation_w3c( presentation_request: Valid indy format presentation request requested_credentials_w3c: W3C format requested credentials credentials_w3c_metadata: W3C format credential metadata - schemas: Indy formatted schemas JSON - credential_definitions: Indy formatted credential definitions JSON - rev_states: Indy format revocation states JSON + schemas: Anoncreds formatted schemas JSON + credential_definitions: Anoncreds formatted credential definitions JSON + rev_states: Anoncreds format revocation states JSON """ present_creds = PresentCredentials() diff --git a/acapy_agent/protocols/present_proof/anoncreds/pres_exch_handler.py b/acapy_agent/protocols/present_proof/anoncreds/pres_exch_handler.py index d1d73f8a72..039f335ef1 100644 --- a/acapy_agent/protocols/present_proof/anoncreds/pres_exch_handler.py +++ b/acapy_agent/protocols/present_proof/anoncreds/pres_exch_handler.py @@ -166,7 +166,8 @@ async def _get_revocation_lists(self, requested_referents: dict, credentials: di result = await anoncreds_registry.get_revocation_list( self._profile, rev_reg_id, - reft_non_revoc_interval.get("to", epoch_now), + timestamp_from=reft_non_revoc_interval.get("from", 0), + timestamp_to=reft_non_revoc_interval.get("to", epoch_now), ) rev_lists[key] = ( diff --git a/demo/runners/faber.py b/demo/runners/faber.py index 00cc9a2e98..5e1322d974 100644 --- a/demo/runners/faber.py +++ b/demo/runners/faber.py @@ -773,7 +773,10 @@ async def main(args): raise Exception( "Error invalid credential type:" + faber_agent.cred_type ) - + log_status( + "Send a proof request to X: " + + json.dumps(proof_request_web_request) + ) await agent.admin_POST( "/present-proof-2.0/send-request", proof_request_web_request ) diff --git a/scenarios/examples/anoncreds_issuance_and_revocation/example.py b/scenarios/examples/anoncreds_issuance_and_revocation/example.py index b38beb64d9..5d2cc1431f 100644 --- a/scenarios/examples/anoncreds_issuance_and_revocation/example.py +++ b/scenarios/examples/anoncreds_issuance_and_revocation/example.py @@ -4,6 +4,7 @@ """ import asyncio +from datetime import datetime from os import getenv from secrets import token_hex @@ -11,7 +12,6 @@ from acapy_controller.logging import logging_to_stdout from acapy_controller.models import ( CreateWalletResponse, - V20PresExRecordList, ) from acapy_controller.protocols import ( DIDResult, @@ -25,7 +25,6 @@ SchemaResultAnoncreds, anoncreds_issue_credential_v2, anoncreds_present_proof_v2, - anoncreds_presentation_summary, ) AGENCY = getenv("AGENCY", "http://agency:3001") @@ -137,13 +136,16 @@ async def main(): ) # Present the the credential's attributes - await anoncreds_present_proof_v2( + _, verifier_ex = await anoncreds_present_proof_v2( holder_anoncreds, issuer, holder_anoncreds_conn.connection_id, issuer_conn_with_anoncreds_holder.connection_id, requested_attributes=[{"name": "firstname"}], + non_revoked={"to": int(datetime.now().timestamp())}, + cred_rev_id=issuer_cred_ex.details.cred_rev_id, ) + assert verifier_ex.verified == "true" # Revoke credential await issuer.post( @@ -160,9 +162,50 @@ async def main(): await holder_anoncreds.record(topic="revocation-notification") + # Present the the credential's attributes + now = int(datetime.now().timestamp()) + _, verifier_ex = await anoncreds_present_proof_v2( + holder_anoncreds, + issuer, + holder_anoncreds_conn.connection_id, + issuer_conn_with_anoncreds_holder.connection_id, + requested_attributes=[{"name": "firstname"}], + non_revoked={"to": now}, + cred_rev_id=issuer_cred_ex.details.cred_rev_id, + ) + assert verifier_ex.verified == "false" + + # Issue another credential + issuer_cred_ex, _ = await anoncreds_issue_credential_v2( + issuer, + holder_anoncreds, + issuer_conn_with_anoncreds_holder.connection_id, + holder_anoncreds_conn.connection_id, + {"firstname": "Anoncreds", "lastname": "Holder"}, + cred_def_id=cred_def.credential_definition_id, + issuer_id=public_did.did, + schema_id=schema.schema_id, + schema_issuer_id=public_did.did, + schema_name=schema_name, + ) + + valid_anoncreds_holder_cred_rev_id = issuer_cred_ex.details.cred_rev_id + + # Holder has one revoked and one non-revoked credential + _, verifier_ex = await anoncreds_present_proof_v2( + holder_anoncreds, + issuer, + holder_anoncreds_conn.connection_id, + issuer_conn_with_anoncreds_holder.connection_id, + requested_attributes=[{"name": "firstname"}], + non_revoked={"to": now}, + cred_rev_id=issuer_cred_ex.details.cred_rev_id, + ) + assert verifier_ex.verified == "true" + """ - This section of the test script demonstrates the issuance, presentation and - revocation of a credential where the issuer and holder are not anoncreds + This section of the test script demonstrates the issuance, presentation and + revocation of a credential where the issuer and holder are not anoncreds capable. Both are askar wallet type. """ @@ -186,22 +229,16 @@ async def main(): ) # Present the the credential's attributes - await anoncreds_present_proof_v2( + _, verifier_ex = await anoncreds_present_proof_v2( holder_indy, issuer, holder_indy_conn.connection_id, issuer_conn_with_indy_holder.connection_id, requested_attributes=[{"name": "firstname"}], + non_revoked={"to": int(datetime.now().timestamp())}, + cred_rev_id=issuer_cred_ex.details.cred_rev_id, ) - # Query presentations - presentations = await issuer.get( - "/present-proof-2.0/records", - response=V20PresExRecordList, - ) - - # Presentation summary - for _, pres in enumerate(presentations.results): - print(anoncreds_presentation_summary(pres)) + assert verifier_ex.verified == "true" # Revoke credential await issuer.post( @@ -218,9 +255,50 @@ async def main(): await holder_indy.record(topic="revocation-notification") - """ + # Presentation after revocation should fail + now = int(datetime.now().timestamp()) + _, verifier_ex = await anoncreds_present_proof_v2( + holder_indy, + issuer, + holder_indy_conn.connection_id, + issuer_conn_with_indy_holder.connection_id, + requested_attributes=[{"name": "firstname"}], + non_revoked={"to": now}, + cred_rev_id=issuer_cred_ex.details.cred_rev_id, + ) + assert verifier_ex.verified == "false" + + # Add another credential to the holder and present it + issuer_cred_ex, _ = await anoncreds_issue_credential_v2( + issuer, + holder_indy, + issuer_conn_with_indy_holder.connection_id, + holder_indy_conn.connection_id, + {"firstname": "Indy", "lastname": "Holder"}, + cred_def_id=cred_def.credential_definition_id, + issuer_id=public_did.did, + schema_id=schema.schema_id, + schema_issuer_id=public_did.did, + schema_name=schema_name, + ) + + valid_indy_holder_cred_rev_id = issuer_cred_ex.details.cred_rev_id + + # Presentation with one revoked and one valid credential + _, verifier_ex = await anoncreds_present_proof_v2( + holder_indy, + issuer, + holder_indy_conn.connection_id, + issuer_conn_with_indy_holder.connection_id, + requested_attributes=[{"name": "firstname"}], + non_revoked={"to": now}, + cred_rev_id=issuer_cred_ex.details.cred_rev_id, + ) + assert verifier_ex.verified == "true" + + """ Upgrade the issuer tenant to anoncreds capable wallet type. When upgrading a - tenant the agent doesn't require a restart. That is why the test is done + tenant the agent doesn't require a restart. That is why the test is done with multitenancy """ await issuer.post( @@ -239,29 +317,35 @@ async def main(): }, ) # Wait for the upgrade to complete - await asyncio.sleep(2) + await asyncio.sleep(1) """ - Do issuance and presentation again after the upgrade. This time the issuer is + Do issuance and presentation again after the upgrade. This time the issuer is an anoncreds capable wallet (wallet type askar-anoncreds). """ # Presentation for anoncreds capable holder on existing credential - await anoncreds_present_proof_v2( + _, verifier_ex = await anoncreds_present_proof_v2( holder_anoncreds, issuer, holder_anoncreds_conn.connection_id, issuer_conn_with_anoncreds_holder.connection_id, requested_attributes=[{"name": "firstname"}], + non_revoked={"to": now}, + cred_rev_id=valid_anoncreds_holder_cred_rev_id, ) + assert verifier_ex.verified == "true" # Presentation for indy capable holder on existing credential - await anoncreds_present_proof_v2( + _, verifier_ex = await anoncreds_present_proof_v2( holder_indy, issuer, holder_indy_conn.connection_id, issuer_conn_with_indy_holder.connection_id, requested_attributes=[{"name": "firstname"}], + non_revoked={"to": now}, + cred_rev_id=valid_indy_holder_cred_rev_id, ) + assert verifier_ex.verified == "true" # Create a new schema and cred def with different attributes on new # anoncreds endpoints @@ -306,13 +390,16 @@ async def main(): schema_name=schema_name, ) # Presentation for anoncreds capable holder - await anoncreds_present_proof_v2( + _, verifier_ex = await anoncreds_present_proof_v2( holder_anoncreds, issuer, holder_anoncreds_conn.connection_id, issuer_conn_with_anoncreds_holder.connection_id, requested_attributes=[{"name": "middlename"}], + non_revoked={"to": int(datetime.now().timestamp())}, + cred_rev_id=issuer_cred_ex.details.cred_rev_id, ) + assert verifier_ex.verified == "true" # Revoke credential await issuer.post( url="/anoncreds/revocation/revoke", @@ -327,6 +414,17 @@ async def main(): ) await holder_anoncreds.record(topic="revocation-notification") + _, verifier_ex = await anoncreds_present_proof_v2( + holder_anoncreds, + issuer, + holder_anoncreds_conn.connection_id, + issuer_conn_with_anoncreds_holder.connection_id, + requested_attributes=[{"name": "middlename"}], + non_revoked={"to": int(datetime.now().timestamp())}, + cred_rev_id=issuer_cred_ex.details.cred_rev_id, + ) + assert verifier_ex.verified == "false" + # Issue a new credential to indy holder issuer_cred_ex, _ = await anoncreds_issue_credential_v2( issuer, @@ -341,13 +439,16 @@ async def main(): schema_name=schema_name, ) # Presentation for indy holder - await anoncreds_present_proof_v2( + _, verifier_ex = await anoncreds_present_proof_v2( holder_indy, issuer, holder_indy_conn.connection_id, issuer_conn_with_indy_holder.connection_id, requested_attributes=[{"name": "middlename"}], + non_revoked={"to": int(datetime.now().timestamp())}, + cred_rev_id=issuer_cred_ex.details.cred_rev_id, ) + assert verifier_ex.verified == "true" # Revoke credential await issuer.post( url="/anoncreds/revocation/revoke", @@ -363,6 +464,17 @@ async def main(): await holder_indy.record(topic="revocation-notification") + _, verifier_ex = await anoncreds_present_proof_v2( + holder_indy, + issuer, + holder_indy_conn.connection_id, + issuer_conn_with_indy_holder.connection_id, + requested_attributes=[{"name": "middlename"}], + non_revoked={"to": int(datetime.now().timestamp())}, + cred_rev_id=issuer_cred_ex.details.cred_rev_id, + ) + assert verifier_ex.verified == "false" + """ This section of the test script demonstrates the issuance, presentation and revocation of a credential where the issuer did not create the schema. diff --git a/scenarios/examples/util.py b/scenarios/examples/util.py index f7d54e15d0..afd165cb99 100644 --- a/scenarios/examples/util.py +++ b/scenarios/examples/util.py @@ -358,6 +358,7 @@ async def anoncreds_present_proof_v2( requested_attributes: Optional[List[Mapping[str, Any]]] = None, requested_predicates: Optional[List[Mapping[str, Any]]] = None, non_revoked: Optional[Mapping[str, int]] = None, + cred_rev_id: Optional[str] = None, ): """Present an credential using present proof v2.""" @@ -412,6 +413,15 @@ async def anoncreds_present_proof_v2( f"/present-proof-2.0/records/{holder_pres_ex_id}/credentials", response=List[CredPrecis], ) + + # Filter credentials by revocation id to allow selecting non-revoked + if cred_rev_id: + relevant_creds = [ + cred + for cred in relevant_creds + if cred.cred_info._extra.get("cred_rev_id") == cred_rev_id + ] + assert holder_pres_ex.by_format.pres_request proof_request = holder_pres_ex.by_format.pres_request.get( "anoncreds" From 59aef0282dcbc9cb0139788b9a58dbccb73ebf05 Mon Sep 17 00:00:00 2001 From: Ian Costanzo Date: Wed, 12 Mar 2025 15:29:16 -0700 Subject: [PATCH 31/76] Anoncreds proof validation issue (once credential has been revoked) (#3557) * Anoncreds proof validation issue - integration test to reproduce error Signed-off-by: Ian Costanzo * Some logging to try to debug the issue Signed-off-by: Ian Costanzo * Repair anoncreds holder revocation list request Signed-off-by: jamshale * Add revocation test to anoncreds scenario Signed-off-by: jamshale * Remove debug logging Signed-off-by: Ian Costanzo * Add release tag Signed-off-by: Ian Costanzo --------- Signed-off-by: Ian Costanzo Signed-off-by: jamshale Co-authored-by: jamshale --- demo/bdd_support/agent_backchannel_client.py | 3 +++ demo/features/0454-present-proof.feature | 27 +++++++++++++++++++ ...cred_data_schema_driverslicense_revoc.json | 8 ++++++ .../cred_data_schema_driverslicense_v2.json | 4 +++ .../data/schema_driverslicense_revoc.json | 3 ++- .../data/schema_driverslicense_v2.json | 3 ++- demo/features/steps/0453-issue-credential.py | 3 +++ demo/runners/agent_container.py | 9 ++++--- 8 files changed, 55 insertions(+), 5 deletions(-) diff --git a/demo/bdd_support/agent_backchannel_client.py b/demo/bdd_support/agent_backchannel_client.py index fa6db011c7..e67db42ed0 100644 --- a/demo/bdd_support/agent_backchannel_client.py +++ b/demo/bdd_support/agent_backchannel_client.py @@ -1,5 +1,6 @@ import asyncio import json +import time import uuid from runners.agent_container import AgentContainer, create_agent_with_args_list @@ -212,6 +213,8 @@ def read_credential_data(schema_name: str, cred_scenario_name: str): for attr in cred_data["attributes"]: if attr["value"] == "@uuid": attr["value"] = str(uuid.uuid4()) + if attr["name"] == "timestamp": + attr["value"] = str(int(time.time())) return cred_data["attributes"] diff --git a/demo/features/0454-present-proof.feature b/demo/features/0454-present-proof.feature index 419ac8a7d4..f14c8a2263 100644 --- a/demo/features/0454-present-proof.feature +++ b/demo/features/0454-present-proof.feature @@ -329,6 +329,33 @@ Feature: RFC 0454 Aries agent present proof | issuer1 | Acme1_capabilities | Bob_cap | Schema_name_1 | Credential_data_1 | Proof_request | | Acme1 | --revocation --public-did --wallet-type askar-anoncreds --cred-type vc_di | --wallet-type askar-anoncreds | driverslicense_v2 | Data_DL_MaxValues | DL_age_over_19_v2 | + @T003-RFC0454.4b + Scenario Outline: Present Proof for a credential where multiple credentials are issued and all but one are revoked + Given we have "3" agents + | name | role | capabilities | + | Acme1 | issuer1 | | + | Bob | prover | | + And "" and "Bob" have an existing connection + And "Bob" has an issued credential from "" + When "" sends a request for proof presentation to "Bob" + Then "" has the proof verified + And "" revokes the credential + When "" sends a request for proof presentation to "Bob" + Then "" has the proof verification fail + When "Bob" has another issued credential from "" + When "" sends a request for proof presentation to "Bob" + Then "" has the proof verified + + @Release @WalletType_Askar + Examples: + | issuer1 | Acme1_capabilities | Bob_cap | Schema_name_1 | Credential_data_1 | Proof_request | + | Acme1 | --revocation --public-did | | driverslicense_v2 | Data_DL_MaxValues | DL_age_over_19_v2 | + + @Release @WalletType_Askar_AnonCreds + Examples: + | issuer1 | Acme1_capabilities | Bob_cap | Schema_name_1 | Credential_data_1 | Proof_request | + | Acme1 | --revocation --public-did --wallet-type askar-anoncreds | --wallet-type askar-anoncreds | driverslicense_v2 | Data_DL_MaxValues | DL_age_over_19_v2 | + @T003-RFC0454.5 Scenario Outline: Present Proof for a vc_di-issued credential using "legacy" indy proof and the proof validates Given we have "2" agents diff --git a/demo/features/data/cred_data_schema_driverslicense_revoc.json b/demo/features/data/cred_data_schema_driverslicense_revoc.json index a9e075ab9b..0b060249d2 100644 --- a/demo/features/data/cred_data_schema_driverslicense_revoc.json +++ b/demo/features/data/cred_data_schema_driverslicense_revoc.json @@ -19,6 +19,10 @@ { "name":"age", "value":"30" + }, + { + "name":"timestamp", + "value":"0" } ] }, @@ -42,6 +46,10 @@ { "name":"age", "value":"15" + }, + { + "name":"timestamp", + "value":"0" } ] } diff --git a/demo/features/data/cred_data_schema_driverslicense_v2.json b/demo/features/data/cred_data_schema_driverslicense_v2.json index bb1d194fec..a459e1609a 100644 --- a/demo/features/data/cred_data_schema_driverslicense_v2.json +++ b/demo/features/data/cred_data_schema_driverslicense_v2.json @@ -19,6 +19,10 @@ { "name":"age", "value":"30" + }, + { + "name":"timestamp", + "value":"0" } ], "filters": { diff --git a/demo/features/data/schema_driverslicense_revoc.json b/demo/features/data/schema_driverslicense_revoc.json index 9f554d0da0..19f492810e 100644 --- a/demo/features/data/schema_driverslicense_revoc.json +++ b/demo/features/data/schema_driverslicense_revoc.json @@ -6,7 +6,8 @@ "address", "DL_number", "expiry", - "age" + "age", + "timestamp" ] }, "cred_def_support_revocation":true diff --git a/demo/features/data/schema_driverslicense_v2.json b/demo/features/data/schema_driverslicense_v2.json index f071dd1c9a..52af742561 100644 --- a/demo/features/data/schema_driverslicense_v2.json +++ b/demo/features/data/schema_driverslicense_v2.json @@ -6,7 +6,8 @@ "address", "DL_number", "expiry", - "age" + "age", + "timestamp" ] }, "cred_def_support_revocation":false diff --git a/demo/features/steps/0453-issue-credential.py b/demo/features/steps/0453-issue-credential.py index b85e5b6ef3..12bc084072 100644 --- a/demo/features/steps/0453-issue-credential.py +++ b/demo/features/steps/0453-issue-credential.py @@ -708,6 +708,9 @@ def step_impl(context, holder, schema_name, credential_data, issuer): @given( '"{holder}" has another issued {schema_name} credential {credential_data} from "{issuer}"' ) +@when( + '"{holder}" has another issued {schema_name} credential {credential_data} from "{issuer}"' +) def step_impl(context, holder, schema_name, credential_data, issuer): context.execute_steps( # TODO possibly check that the requested schema is "active" (if there are multiple schemas) diff --git a/demo/runners/agent_container.py b/demo/runners/agent_container.py index e529e6aefe..305689f1c6 100644 --- a/demo/runners/agent_container.py +++ b/demo/runners/agent_container.py @@ -448,6 +448,7 @@ async def handle_present_proof(self, message): f"/present-proof/records/{presentation_exchange_id}/verify-presentation" ) self.log("Proof =", proof["verified"]) + self.last_proof_received = proof elif state == "abandoned": log_status("Presentation exchange abandoned") @@ -625,9 +626,11 @@ async def handle_present_proof_v2_0(self, message): proof = await self.admin_POST( f"/present-proof-2.0/records/{pres_ex_id}/verify-presentation" ) - self.log("Proof =", proof["verified"]) + self.log("Proof 2.0 =", proof["verified"]) self.last_proof_received = proof + log_status(f">>> last proof received: {self.last_proof_received}") + elif state == "abandoned": log_status("Presentation exchange abandoned") self.log("Problem report message:", message.get("error_msg")) @@ -1080,6 +1083,8 @@ async def request_proof( ): log_status("#20 Request proof of degree from alice") + self.last_proof_received = None + if self.cred_type in [CRED_FORMAT_ANONCREDS, CRED_FORMAT_INDY, CRED_FORMAT_VC_DI]: proof_request = { "name": ( @@ -1161,8 +1166,6 @@ async def verify_proof(self, proof_request): print("No proof received") return None - # log_status(f">>> last proof received: {self.agent.last_proof_received}") - if self.cred_type in [CRED_FORMAT_ANONCREDS, CRED_FORMAT_INDY, CRED_FORMAT_VC_DI]: # return verified status return self.agent.last_proof_received["verified"] From 6720b7a9e99c6dd149b72ccfd83d1457c5818497 Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Fri, 14 Mar 2025 18:18:49 +0200 Subject: [PATCH 32/76] :sparkles: Refactor TailsServer injection pattern (#3587) * :sparkles: Remove TailsServer injection Resolves #3586 Signed-off-by: ff137 * :white_check_mark: Fix tests Signed-off-by: ff137 --------- Signed-off-by: ff137 --- acapy_agent/anoncreds/revocation.py | 10 +-- .../anoncreds/tests/test_revocation.py | 79 +++++++++---------- acapy_agent/config/default_context.py | 17 ---- .../models/issuer_rev_reg_record.py | 6 +- .../tests/test_issuer_rev_reg_record.py | 14 +++- acapy_agent/tails/indy_tails_server.py | 6 +- 6 files changed, 55 insertions(+), 77 deletions(-) diff --git a/acapy_agent/anoncreds/revocation.py b/acapy_agent/anoncreds/revocation.py index ad96dfe4cc..e8cb94bcd1 100644 --- a/acapy_agent/anoncreds/revocation.py +++ b/acapy_agent/anoncreds/revocation.py @@ -30,9 +30,7 @@ from ..core.error import BaseError from ..core.event_bus import Event, EventBus from ..core.profile import Profile, ProfileSession -from ..multitenant.base import BaseMultitenantManager from ..tails.anoncreds_tails_server import AnonCredsTailsServer -from ..tails.base import BaseTailsServer from .error_messages import ANONCREDS_PROFILE_REQUIRED_MSG from .events import RevListFinishedEvent, RevRegDefFinishedEvent from .issuer import ( @@ -694,14 +692,8 @@ def get_local_tails_path(self, rev_reg_def: RevRegDef) -> str: async def upload_tails_file(self, rev_reg_def: RevRegDef): """Upload the local tails file to the tails server.""" - multitenant_mgr = self.profile.inject_or(BaseMultitenantManager) - if multitenant_mgr: - tails_server = AnonCredsTailsServer() - else: - tails_server = self.profile.inject_or(BaseTailsServer) + tails_server = AnonCredsTailsServer() - if not tails_server: - raise AnonCredsRevocationError("Tails server not configured") if not Path(self.get_local_tails_path(rev_reg_def)).is_file(): raise AnonCredsRevocationError("Local tails file not found") diff --git a/acapy_agent/anoncreds/tests/test_revocation.py b/acapy_agent/anoncreds/tests/test_revocation.py index 2d9bc62e15..f56d552dde 100644 --- a/acapy_agent/anoncreds/tests/test_revocation.py +++ b/acapy_agent/anoncreds/tests/test_revocation.py @@ -26,15 +26,13 @@ RevRegDefState, RevRegDefValue, ) -from ...anoncreds.models.schema import ( - AnonCredsSchema, - GetSchemaResult, -) +from ...anoncreds.models.schema import AnonCredsSchema, GetSchemaResult from ...anoncreds.registry import AnonCredsRegistry from ...anoncreds.tests.mock_objects import MOCK_REV_REG_DEF from ...anoncreds.tests.test_issuer import MockCredDefEntry from ...askar.profile_anon import AskarAnoncredsProfileSession from ...core.event_bus import Event, EventBus, MockEventBus +from ...tails.anoncreds_tails_server import AnonCredsTailsServer from ...tests import mock from ...utils.testing import create_test_profile from .. import revocation as test_module @@ -835,48 +833,49 @@ def test_generate_public_tails_uri(self): self.revocation.generate_public_tails_uri(rev_reg_def) async def test_upload_tails_file(self): - self.profile.inject_or = mock.Mock( - side_effect=[ - None, - mock.MagicMock( - upload_tails_file=mock.CoroutineMock( - return_value=(True, "https://tails-server.com") - ) - ), - ] + tails_server = mock.MagicMock(AnonCredsTailsServer, autospec=True) + tails_server.upload_tails_file = mock.CoroutineMock( + return_value=(True, "https://tails-server.com") ) + # valid - await self.revocation.upload_tails_file(rev_reg_def) + with mock.patch.object( + test_module, + "AnonCredsTailsServer", + mock.MagicMock(return_value=tails_server), + ): + await self.revocation.upload_tails_file(rev_reg_def) + tails_server.upload_tails_file.assert_called_once() + # upload fails - self.profile.inject_or = mock.Mock( - side_effect=[ - None, - mock.MagicMock( - upload_tails_file=mock.CoroutineMock( - return_value=(None, "https://tails-server.com"), - ) - ), - ] - ) - with self.assertRaises(test_module.AnonCredsRevocationError): + tails_server.upload_tails_file.reset_mock() + tails_server.upload_tails_file = mock.CoroutineMock( + return_value=(None, "https://tails-server.com") + ) + with ( + mock.patch.object( + test_module, + "AnonCredsTailsServer", + mock.MagicMock(return_value=tails_server), + ), + self.assertRaises(test_module.AnonCredsRevocationError), + ): await self.revocation.upload_tails_file(rev_reg_def) - self.profile.inject_or = mock.Mock( - side_effect=[ - None, - mock.MagicMock( - upload_tails_file=mock.CoroutineMock( - return_value=(True, "not-http://tails-server.com"), - ) - ), - ] + + tails_server.upload_tails_file.reset_mock() + tails_server.upload_tails_file = mock.CoroutineMock( + return_value=(None, "not-https://tails-server.com") ) - # tails location does not match - with self.assertRaises(test_module.AnonCredsRevocationError): - await self.revocation.upload_tails_file(rev_reg_def) - # tails server base url setting is missing - self.profile.inject_or = mock.Mock(return_value=None) - with self.assertRaises(test_module.AnonCredsRevocationError): + # tails location does not match + with ( + mock.patch.object( + test_module, + "AnonCredsTailsServer", + mock.MagicMock(return_value=tails_server), + ), + self.assertRaises(test_module.AnonCredsRevocationError), + ): await self.revocation.upload_tails_file(rev_reg_def) @mock.patch.object(AskarAnoncredsProfileSession, "handle") diff --git a/acapy_agent/config/default_context.py b/acapy_agent/config/default_context.py index 22a3b021da..170c3c089e 100644 --- a/acapy_agent/config/default_context.py +++ b/acapy_agent/config/default_context.py @@ -14,7 +14,6 @@ from ..protocols.introduction.v0_1.base_service import BaseIntroductionService from ..protocols.introduction.v0_1.demo_service import DemoIntroductionService from ..resolver.did_resolver import DIDResolver -from ..tails.base import BaseTailsServer from ..transport.wire_format import BaseWireFormat from ..utils.stats import Collector from ..wallet.default_verification_key_strategy import ( @@ -85,22 +84,6 @@ async def bind_providers(self, context: InjectionContext): context.injector.bind_provider(ProfileManager, ProfileManagerProvider()) - wallet_type = self.settings.get("wallet.type") - if wallet_type == "askar-anoncreds": - context.injector.bind_provider( - BaseTailsServer, - ClassProvider( - "acapy_agent.tails.anoncreds_tails_server.AnonCredsTailsServer", - ), - ) - else: - context.injector.bind_provider( - BaseTailsServer, - ClassProvider( - "acapy_agent.tails.indy_tails_server.IndyTailsServer", - ), - ) - # Register default pack format context.injector.bind_provider( BaseWireFormat, diff --git a/acapy_agent/revocation/models/issuer_rev_reg_record.py b/acapy_agent/revocation/models/issuer_rev_reg_record.py index ae10137695..fe02445fa2 100644 --- a/acapy_agent/revocation/models/issuer_rev_reg_record.py +++ b/acapy_agent/revocation/models/issuer_rev_reg_record.py @@ -41,7 +41,7 @@ INDY_REV_REG_ID_VALIDATE, UUID4_EXAMPLE, ) -from ...tails.base import BaseTailsServer +from ...tails.indy_tails_server import IndyTailsServer from ..error import RevocationError from ..recover import generate_ledger_rrrecovery_txn from .issuer_cred_rev_record import IssuerCredRevRecord @@ -474,9 +474,7 @@ def has_local_tails_file(self) -> bool: async def upload_tails_file(self, profile: Profile): """Upload the local tails file to the tails server.""" - tails_server = profile.inject_or(BaseTailsServer) - if not tails_server: - raise RevocationError("Tails server not configured") + tails_server = IndyTailsServer() if not self.has_local_tails_file: raise RevocationError("Local tails file not found") diff --git a/acapy_agent/revocation/models/tests/test_issuer_rev_reg_record.py b/acapy_agent/revocation/models/tests/test_issuer_rev_reg_record.py index 12488dd350..dc6e9322bf 100644 --- a/acapy_agent/revocation/models/tests/test_issuer_rev_reg_record.py +++ b/acapy_agent/revocation/models/tests/test_issuer_rev_reg_record.py @@ -7,7 +7,7 @@ from ....indy.issuer import IndyIssuer, IndyIssuerError from ....indy.util import indy_client_dir from ....ledger.base import BaseLedger -from ....tails.base import BaseTailsServer +from ....tails.indy_tails_server import IndyTailsServer from ....tests import mock from ....utils.testing import create_test_profile from ...error import RevocationError @@ -60,11 +60,10 @@ async def asyncSetUp(self): self.ledger.send_revoc_reg_entry = mock.CoroutineMock() self.profile.context.injector.bind_instance(BaseLedger, self.ledger) - self.tails_server = mock.MagicMock(BaseTailsServer, autospec=True) + self.tails_server = mock.MagicMock(IndyTailsServer, autospec=True) self.tails_server.upload_tails_file = mock.CoroutineMock( return_value=(True, "http://1.2.3.4:8088/rev-reg-id") ) - self.profile.context.injector.bind_instance(BaseTailsServer, self.tails_server) self.session = await self.profile.session() @@ -271,7 +270,14 @@ async def test_generate_registry_etc(self): assert rec.state == IssuerRevRegRecord.STATE_POSTED self.ledger.send_revoc_reg_def.assert_called_once() - with mock.patch.object(test_module.Path, "is_file", lambda _: True): + with ( + mock.patch.object(test_module.Path, "is_file", lambda _: True), + mock.patch.object( + test_module, + "IndyTailsServer", + mock.MagicMock(return_value=self.tails_server), + ), + ): await rec.upload_tails_file(self.profile) assert ( rec.tails_public_uri diff --git a/acapy_agent/tails/indy_tails_server.py b/acapy_agent/tails/indy_tails_server.py index 88617e521b..c130c2057c 100644 --- a/acapy_agent/tails/indy_tails_server.py +++ b/acapy_agent/tails/indy_tails_server.py @@ -47,10 +47,10 @@ async def upload_tails_file( ledger_manager = context.injector.inject(BaseMultipleLedgerManager) write_ledger = context.injector.inject(BaseLedger) available_write_ledgers = await ledger_manager.get_write_ledgers() - LOGGER.debug(f"available write_ledgers = {available_write_ledgers}") - LOGGER.debug(f"write_ledger = {write_ledger}") + LOGGER.debug("available write_ledgers = %s", available_write_ledgers) + LOGGER.debug("write_ledger = %s", write_ledger) pool = write_ledger.pool - LOGGER.debug(f"write_ledger pool = {pool}") + LOGGER.debug("write_ledger pool = %s", pool) genesis_transactions = pool.genesis_txns From 4fbd84fc53f0daf3702c7719c37279efdc8f24de Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Fri, 14 Mar 2025 20:05:36 +0200 Subject: [PATCH 33/76] :memo: Update README (#3588) Signed-off-by: ff137 Co-authored-by: Stephen Curran --- README.md | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a737fad8c8..9924a2de3b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,14 @@ # ACA-Py -- A Cloud Agent - Python -🚨 **ACA-Py is part of the [OpenWallet Foundation] (OWF)!** 🚨 +![Python](https://img.shields.io/badge/python-3.12-blue.svg) +[![PyPI version](https://img.shields.io/pypi/v/acapy-agent)](https://pypi.org/project/acapy-agent/) +[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=openwallet-foundation_acapy&metric=ncloc)](https://sonarcloud.io/summary/new_code?id=openwallet-foundation_acapy) +[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=openwallet-foundation_acapy&metric=coverage)](https://sonarcloud.io/summary/new_code?id=openwallet-foundation_acapy) +[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=openwallet-foundation_acapy&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=openwallet-foundation_acapy) +[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=openwallet-foundation_acapy&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=openwallet-foundation_acapy) +[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/openwallet-foundation/acapy/badge)](https://scorecard.dev/viewer/?uri=github.com/openwallet-foundation/acapy) -[OpenWallet Foundation]: https://openwallet.foundation/ +> **ACA-Py is now part of the [OpenWallet Foundation](https://openwallet.foundation/) (OWF)!** The move of ACA-Py to the OWF is now complete. If you haven't done so already, please update your ACA-Py deployment to use: @@ -10,17 +16,9 @@ The move of ACA-Py to the OWF is now complete. If you haven't done so already, p - the new [acapy-agent in PyPi](https://pypi.org/project/acapy-agent/), and - the container images for ACA-Py hosted by the OpenWallet Foundation GitHub organization within the GitHub Container Repository (GHCR). -

- - - - -   -   -   -

- -> An easy to use enterprise wallet for building decentralized trust services using any language that supports sending/receiving HTTP requests. +___ + +ACA-Py is an easy to use enterprise SSI agent for building decentralized trust services using any language that supports sending/receiving HTTP requests. Full access to an organized set of all of the ACA-Py documents is available at [https://aca-py.org](https://aca-py.org). Check it out! It's much easier to navigate than the ACA-Py GitHub repo for reading the documentation. From 16c6cee2d2667fe2bdf8924981d3f88c2fafb405 Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Fri, 14 Mar 2025 21:14:14 +0200 Subject: [PATCH 34/76] :bug: Fix: Register both askar and anoncreds plugins for multitenancy (#3585) * :bug: Register both askar and anoncreds plugins when multitenancy enabled Signed-off-by: ff137 * :sparkles: Add logging Signed-off-by: ff137 * :art: Signed-off-by: ff137 * :art: Deduplicate Signed-off-by: ff137 * :white_check_mark: Test coverage for registering askar/anoncreds plugins Signed-off-by: ff137 --------- Signed-off-by: ff137 Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- acapy_agent/config/default_context.py | 54 ++++++++------ .../config/tests/test_default_context.py | 74 +++++++++++++++++++ 2 files changed, 107 insertions(+), 21 deletions(-) diff --git a/acapy_agent/config/default_context.py b/acapy_agent/config/default_context.py index 170c3c089e..9b1c99d0f7 100644 --- a/acapy_agent/config/default_context.py +++ b/acapy_agent/config/default_context.py @@ -1,5 +1,7 @@ """Classes for configuring the default injection context.""" +import logging + from ..anoncreds.registry import AnonCredsRegistry from ..cache.base import BaseCache from ..cache.in_memory import InMemoryCache @@ -26,6 +28,8 @@ from .injection_context import InjectionContext from .provider import CachedProvider, ClassProvider +LOGGER = logging.getLogger(__name__) + class DefaultContextBuilder(ContextBuilder): """Default context builder.""" @@ -63,11 +67,7 @@ async def build_context(self) -> InjectionContext: # DIDComm Messaging if context.settings.get("experiment.didcomm_v2"): - from didcomm_messaging import ( - CryptoService, - PackagingService, - RoutingService, - ) + from didcomm_messaging import CryptoService, PackagingService, RoutingService from didcomm_messaging.crypto.backend.askar import AskarCryptoService context.injector.bind_instance(CryptoService, AskarCryptoService()) @@ -120,22 +120,29 @@ async def load_plugins(self, context: InjectionContext): if not self.settings.get("transport.disabled"): plugin_registry.register_package("acapy_agent.protocols") - # Currently providing admin routes only - plugin_registry.register_plugin("acapy_agent.holder") + # Define core plugins + core_plugins = [ + "acapy_agent.holder", + "acapy_agent.ledger", + "acapy_agent.connections", + "acapy_agent.messaging.jsonld", + "acapy_agent.resolver", + "acapy_agent.settings", + "acapy_agent.vc", + "acapy_agent.vc.data_integrity", + "acapy_agent.wallet", + "acapy_agent.wallet.keys", + ] - plugin_registry.register_plugin("acapy_agent.ledger") + did_management_plugins = [ + "acapy_agent.did.indy", + ] - plugin_registry.register_plugin("acapy_agent.connections") - plugin_registry.register_plugin("acapy_agent.messaging.jsonld") - plugin_registry.register_plugin("acapy_agent.resolver") - plugin_registry.register_plugin("acapy_agent.settings") - plugin_registry.register_plugin("acapy_agent.vc") - plugin_registry.register_plugin("acapy_agent.vc.data_integrity") - plugin_registry.register_plugin("acapy_agent.wallet") - plugin_registry.register_plugin("acapy_agent.wallet.keys") + default_plugins = core_plugins + did_management_plugins - # Did management plugins - plugin_registry.register_plugin("acapy_agent.did.indy") + LOGGER.info("Registering default plugins") + for plugin in default_plugins: + plugin_registry.register_plugin(plugin) anoncreds_plugins = [ "acapy_agent.anoncreds", @@ -152,22 +159,27 @@ async def load_plugins(self, context: InjectionContext): ] def register_askar_plugins(): + LOGGER.info("Registering askar plugins") for plugin in askar_plugins: plugin_registry.register_plugin(plugin) def register_anoncreds_plugins(): + LOGGER.info("Registering anoncreds plugins") for plugin in anoncreds_plugins: plugin_registry.register_plugin(plugin) - if wallet_type == "askar-anoncreds": + if context.settings.get("multitenant.enabled"): + # Register both askar and anoncreds plugins for multitenancy + register_askar_plugins() + register_anoncreds_plugins() + elif wallet_type == "askar-anoncreds": register_anoncreds_plugins() else: register_askar_plugins() if context.settings.get("multitenant.admin_enabled"): + LOGGER.info("Registering multitenant admin API plugin") plugin_registry.register_plugin("acapy_agent.multitenant.admin") - register_askar_plugins() - register_anoncreds_plugins() # Register external plugins for plugin_path in self.settings.get("external_plugins", []): diff --git a/acapy_agent/config/tests/test_default_context.py b/acapy_agent/config/tests/test_default_context.py index 1c75772a37..923ecbef14 100644 --- a/acapy_agent/config/tests/test_default_context.py +++ b/acapy_agent/config/tests/test_default_context.py @@ -2,6 +2,7 @@ from unittest import IsolatedAsyncioTestCase from ...cache.base import BaseCache +from ...core.plugin_registry import PluginRegistry from ...core.profile import ProfileManager from ...core.protocol_registry import ProtocolRegistry from ...transport.wire_format import BaseWireFormat @@ -29,8 +30,81 @@ async def test_build_context(self): settings={ "timing.enabled": True, "timing.log.file": NamedTemporaryFile().name, + "multitenant.enabled": True, "multitenant.admin_enabled": True, } ) result = await builder.build_context() assert isinstance(result, InjectionContext) + + async def test_plugin_registration_askar_anoncreds(self): + """Test anoncreds plugins are registered when wallet_type is askar-anoncreds.""" + builder = DefaultContextBuilder( + settings={ + "wallet.type": "askar-anoncreds", + } + ) + result = await builder.build_context() + plugin_registry = result.inject(PluginRegistry) + + # Check that anoncreds plugins are registered + for plugin in [ + "acapy_agent.anoncreds", + "acapy_agent.anoncreds.default.did_indy", + "acapy_agent.anoncreds.default.did_web", + "acapy_agent.anoncreds.default.legacy_indy", + "acapy_agent.revocation_anoncreds", + ]: + assert plugin in plugin_registry.plugin_names + + async def test_plugin_registration_multitenant_enabled(self): + """Test anoncreds plugins are registered when multitenant is enabled.""" + builder = DefaultContextBuilder( + settings={ + "multitenant.enabled": True, + } + ) + result = await builder.build_context() + plugin_registry = result.inject(PluginRegistry) + + # Check that anoncreds and askar plugins are registered + for plugin in [ + "acapy_agent.anoncreds", + "acapy_agent.anoncreds.default.did_indy", + "acapy_agent.anoncreds.default.did_web", + "acapy_agent.anoncreds.default.legacy_indy", + "acapy_agent.revocation_anoncreds", + "acapy_agent.messaging.credential_definitions", + "acapy_agent.messaging.schemas", + "acapy_agent.revocation", + ]: + assert plugin in plugin_registry.plugin_names + + async def test_plugin_registration_askar_only(self): + """Test only askar plugins are registered when wallet_type is askar and multitenant is not enabled.""" + builder = DefaultContextBuilder( + settings={ + "wallet.type": "askar", + "multitenant.enabled": False, + } + ) + result = await builder.build_context() + plugin_registry = result.inject(PluginRegistry) + + # Check that only askar plugins are registered + for plugin in [ + "acapy_agent.messaging.credential_definitions", + "acapy_agent.messaging.schemas", + "acapy_agent.revocation", + ]: + assert plugin in plugin_registry.plugin_names + + # Ensure anoncreds plugins are not registered + for plugin in [ + "acapy_agent.anoncreds", + "acapy_agent.anoncreds.default.did_indy", + "acapy_agent.anoncreds.default.did_web", + "acapy_agent.anoncreds.default.legacy_indy", + "acapy_agent.revocation_anoncreds", + ]: + assert plugin not in plugin_registry.plugin_names From d4ac79491b03fe7c5dad57e5ae90a1b73de2e4d1 Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Sat, 15 Mar 2025 01:03:48 +0200 Subject: [PATCH 35/76] :arrow_up: Upgrade ruff to 0.11 (#3589) --- .github/workflows/format.yml | 2 +- .pre-commit-config.yaml | 2 +- poetry.lock | 44 ++++++++++++++++++------------------ pyproject.toml | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 9970591437..3b00c7d47a 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -17,5 +17,5 @@ jobs: - name: Ruff Format and Lint Check uses: chartboost/ruff-action@v1 with: - version: 0.9.2 + version: 0.11.0 args: "format --check" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0dae0431dd..47c6a257e3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,7 +8,7 @@ repos: additional_dependencies: ['@commitlint/config-conventional'] - repo: https://github.com/astral-sh/ruff-pre-commit # Ensure this is synced with pyproject.toml - rev: v0.9.2 + rev: v0.11.0 hooks: # Run the linter - id: ruff diff --git a/poetry.lock b/poetry.lock index 9b33e5b265..b3154c3b10 100644 --- a/poetry.lock +++ b/poetry.lock @@ -627,6 +627,7 @@ files = [ {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:60eb32934076fa07e4316b7b2742fa52cbb190b42c2df2863dbc4230a0a9b385"}, {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e"}, {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e"}, {file = "cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053"}, @@ -637,6 +638,7 @@ files = [ {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9abcc2e083cbe8dde89124a47e5e53ec38751f0d7dfd36801008f316a127d7ba"}, {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64"}, {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285"}, {file = "cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417"}, @@ -1304,8 +1306,6 @@ python-versions = "*" groups = ["main"] files = [ {file = "jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c"}, - {file = "jsonpath_ng-1.7.0-py2-none-any.whl", hash = "sha256:898c93fc173f0c336784a3fa63d7434297544b7198124a68f9a3ef9597b0ae6e"}, - {file = "jsonpath_ng-1.7.0-py3-none-any.whl", hash = "sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6"}, ] [package.dependencies] @@ -2620,30 +2620,30 @@ test = ["hypothesis (>=6.22.0,<6.108.7)", "pytest (>=7.0.0)", "pytest-xdist (>=2 [[package]] name = "ruff" -version = "0.9.6" +version = "0.11.0" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.9.6-py3-none-linux_armv6l.whl", hash = "sha256:2f218f356dd2d995839f1941322ff021c72a492c470f0b26a34f844c29cdf5ba"}, - {file = "ruff-0.9.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b908ff4df65dad7b251c9968a2e4560836d8f5487c2f0cc238321ed951ea0504"}, - {file = "ruff-0.9.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b109c0ad2ececf42e75fa99dc4043ff72a357436bb171900714a9ea581ddef83"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1de4367cca3dac99bcbd15c161404e849bb0bfd543664db39232648dc00112dc"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac3ee4d7c2c92ddfdaedf0bf31b2b176fa7aa8950efc454628d477394d35638b"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dc1edd1775270e6aa2386119aea692039781429f0be1e0949ea5884e011aa8e"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4a091729086dffa4bd070aa5dab7e39cc6b9d62eb2bef8f3d91172d30d599666"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1bbc6808bf7b15796cef0815e1dfb796fbd383e7dbd4334709642649625e7c5"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:589d1d9f25b5754ff230dce914a174a7c951a85a4e9270613a2b74231fdac2f5"}, - {file = "ruff-0.9.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc61dd5131742e21103fbbdcad683a8813be0e3c204472d520d9a5021ca8b217"}, - {file = "ruff-0.9.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5e2d9126161d0357e5c8f30b0bd6168d2c3872372f14481136d13de9937f79b6"}, - {file = "ruff-0.9.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:68660eab1a8e65babb5229a1f97b46e3120923757a68b5413d8561f8a85d4897"}, - {file = "ruff-0.9.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c4cae6c4cc7b9b4017c71114115db0445b00a16de3bcde0946273e8392856f08"}, - {file = "ruff-0.9.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:19f505b643228b417c1111a2a536424ddde0db4ef9023b9e04a46ed8a1cb4656"}, - {file = "ruff-0.9.6-py3-none-win32.whl", hash = "sha256:194d8402bceef1b31164909540a597e0d913c0e4952015a5b40e28c146121b5d"}, - {file = "ruff-0.9.6-py3-none-win_amd64.whl", hash = "sha256:03482d5c09d90d4ee3f40d97578423698ad895c87314c4de39ed2af945633caa"}, - {file = "ruff-0.9.6-py3-none-win_arm64.whl", hash = "sha256:0e2bb706a2be7ddfea4a4af918562fdc1bcb16df255e5fa595bbd800ce322a5a"}, - {file = "ruff-0.9.6.tar.gz", hash = "sha256:81761592f72b620ec8fa1068a6fd00e98a5ebee342a3642efd84454f3031dca9"}, + {file = "ruff-0.11.0-py3-none-linux_armv6l.whl", hash = "sha256:dc67e32bc3b29557513eb7eeabb23efdb25753684b913bebb8a0c62495095acb"}, + {file = "ruff-0.11.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:38c23fd9bdec4eb437b4c1e3595905a0a8edfccd63a790f818b28c78fe345639"}, + {file = "ruff-0.11.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7c8661b0be91a38bd56db593e9331beaf9064a79028adee2d5f392674bbc5e88"}, + {file = "ruff-0.11.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b6c0e8d3d2db7e9f6efd884f44b8dc542d5b6b590fc4bb334fdbc624d93a29a2"}, + {file = "ruff-0.11.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c3156d3f4b42e57247275a0a7e15a851c165a4fc89c5e8fa30ea6da4f7407b8"}, + {file = "ruff-0.11.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:490b1e147c1260545f6d041c4092483e3f6d8eba81dc2875eaebcf9140b53905"}, + {file = "ruff-0.11.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1bc09a7419e09662983b1312f6fa5dab829d6ab5d11f18c3760be7ca521c9329"}, + {file = "ruff-0.11.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcfa478daf61ac8002214eb2ca5f3e9365048506a9d52b11bea3ecea822bb844"}, + {file = "ruff-0.11.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6fbb2aed66fe742a6a3a0075ed467a459b7cedc5ae01008340075909d819df1e"}, + {file = "ruff-0.11.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92c0c1ff014351c0b0cdfdb1e35fa83b780f1e065667167bb9502d47ca41e6db"}, + {file = "ruff-0.11.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e4fd5ff5de5f83e0458a138e8a869c7c5e907541aec32b707f57cf9a5e124445"}, + {file = "ruff-0.11.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:96bc89a5c5fd21a04939773f9e0e276308be0935de06845110f43fd5c2e4ead7"}, + {file = "ruff-0.11.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a9352b9d767889ec5df1483f94870564e8102d4d7e99da52ebf564b882cdc2c7"}, + {file = "ruff-0.11.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:049a191969a10897fe052ef9cc7491b3ef6de79acd7790af7d7897b7a9bfbcb6"}, + {file = "ruff-0.11.0-py3-none-win32.whl", hash = "sha256:3191e9116b6b5bbe187447656f0c8526f0d36b6fd89ad78ccaad6bdc2fad7df2"}, + {file = "ruff-0.11.0-py3-none-win_amd64.whl", hash = "sha256:c58bfa00e740ca0a6c43d41fb004cd22d165302f360aaa56f7126d544db31a21"}, + {file = "ruff-0.11.0-py3-none-win_arm64.whl", hash = "sha256:868364fc23f5aa122b00c6f794211e85f7e78f5dffdf7c590ab90b8c4e69b657"}, + {file = "ruff-0.11.0.tar.gz", hash = "sha256:e55c620690a4a7ee6f1cccb256ec2157dc597d109400ae75bbf944fc9d6462e2"}, ] [[package]] @@ -2954,4 +2954,4 @@ didcommv2 = ["didcomm-messaging"] [metadata] lock-version = "2.1" python-versions = "^3.12" -content-hash = "1176053f084869dafc9f1754b0eed17985beadc7b99dcbefd8290e86853bac55" +content-hash = "b476357bba4064d09cd600fd975a732c1483d9071bab6a31e493dedd4aaf272f" diff --git a/pyproject.toml b/pyproject.toml index 91be2f7193..e2531ccd17 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,7 +70,7 @@ canonicaljson = "^2.0.0" [tool.poetry.group.dev.dependencies] # Sync with version in .pre-commit-config.yaml and .github/workflows/format.yml -ruff = "~0.9.6" +ruff = "~0.11.0" pre-commit = "~4.1.0" From 5dac5b8b2902f9fddf407404f4991db59563d206 Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Sat, 15 Mar 2025 16:31:52 +0200 Subject: [PATCH 36/76] :arrow_up: Update lock file (#3590) Signed-off-by: ff137 --- poetry.lock | 1017 ++++++++++++++++++++++++++------------------------- 1 file changed, 518 insertions(+), 499 deletions(-) diff --git a/poetry.lock b/poetry.lock index b3154c3b10..d3f3976668 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,105 +2,105 @@ [[package]] name = "aiohappyeyeballs" -version = "2.4.4" +version = "2.6.1" description = "Happy Eyeballs for asyncio" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohappyeyeballs-2.4.4-py3-none-any.whl", hash = "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8"}, - {file = "aiohappyeyeballs-2.4.4.tar.gz", hash = "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745"}, + {file = "aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"}, + {file = "aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558"}, ] [[package]] name = "aiohttp" -version = "3.11.12" +version = "3.11.13" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohttp-3.11.12-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:aa8a8caca81c0a3e765f19c6953416c58e2f4cc1b84829af01dd1c771bb2f91f"}, - {file = "aiohttp-3.11.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84ede78acde96ca57f6cf8ccb8a13fbaf569f6011b9a52f870c662d4dc8cd854"}, - {file = "aiohttp-3.11.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:584096938a001378484aa4ee54e05dc79c7b9dd933e271c744a97b3b6f644957"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:392432a2dde22b86f70dd4a0e9671a349446c93965f261dbaecfaf28813e5c42"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:88d385b8e7f3a870146bf5ea31786ef7463e99eb59e31db56e2315535d811f55"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b10a47e5390c4b30a0d58ee12581003be52eedd506862ab7f97da7a66805befb"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b5263dcede17b6b0c41ef0c3ccce847d82a7da98709e75cf7efde3e9e3b5cae"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50c5c7b8aa5443304c55c262c5693b108c35a3b61ef961f1e782dd52a2f559c7"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1c031a7572f62f66f1257db37ddab4cb98bfaf9b9434a3b4840bf3560f5e788"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:7e44eba534381dd2687be50cbd5f2daded21575242ecfdaf86bbeecbc38dae8e"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:145a73850926018ec1681e734cedcf2716d6a8697d90da11284043b745c286d5"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:2c311e2f63e42c1bf86361d11e2c4a59f25d9e7aabdbdf53dc38b885c5435cdb"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ea756b5a7bac046d202a9a3889b9a92219f885481d78cd318db85b15cc0b7bcf"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:526c900397f3bbc2db9cb360ce9c35134c908961cdd0ac25b1ae6ffcaa2507ff"}, - {file = "aiohttp-3.11.12-cp310-cp310-win32.whl", hash = "sha256:b8d3bb96c147b39c02d3db086899679f31958c5d81c494ef0fc9ef5bb1359b3d"}, - {file = "aiohttp-3.11.12-cp310-cp310-win_amd64.whl", hash = "sha256:7fe3d65279bfbee8de0fb4f8c17fc4e893eed2dba21b2f680e930cc2b09075c5"}, - {file = "aiohttp-3.11.12-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:87a2e00bf17da098d90d4145375f1d985a81605267e7f9377ff94e55c5d769eb"}, - {file = "aiohttp-3.11.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b34508f1cd928ce915ed09682d11307ba4b37d0708d1f28e5774c07a7674cac9"}, - {file = "aiohttp-3.11.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:936d8a4f0f7081327014742cd51d320296b56aa6d324461a13724ab05f4b2933"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de1378f72def7dfb5dbd73d86c19eda0ea7b0a6873910cc37d57e80f10d64e1"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9d45dbb3aaec05cf01525ee1a7ac72de46a8c425cb75c003acd29f76b1ffe94"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:930ffa1925393381e1e0a9b82137fa7b34c92a019b521cf9f41263976666a0d6"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8340def6737118f5429a5df4e88f440746b791f8f1c4ce4ad8a595f42c980bd5"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4016e383f91f2814e48ed61e6bda7d24c4d7f2402c75dd28f7e1027ae44ea204"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3c0600bcc1adfaaac321422d615939ef300df81e165f6522ad096b73439c0f58"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:0450ada317a65383b7cce9576096150fdb97396dcfe559109b403c7242faffef"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:850ff6155371fd802a280f8d369d4e15d69434651b844bde566ce97ee2277420"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8fd12d0f989c6099e7b0f30dc6e0d1e05499f3337461f0b2b0dadea6c64b89df"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:76719dd521c20a58a6c256d058547b3a9595d1d885b830013366e27011ffe804"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:97fe431f2ed646a3b56142fc81d238abcbaff08548d6912acb0b19a0cadc146b"}, - {file = "aiohttp-3.11.12-cp311-cp311-win32.whl", hash = "sha256:e10c440d142fa8b32cfdb194caf60ceeceb3e49807072e0dc3a8887ea80e8c16"}, - {file = "aiohttp-3.11.12-cp311-cp311-win_amd64.whl", hash = "sha256:246067ba0cf5560cf42e775069c5d80a8989d14a7ded21af529a4e10e3e0f0e6"}, - {file = "aiohttp-3.11.12-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e392804a38353900c3fd8b7cacbea5132888f7129f8e241915e90b85f00e3250"}, - {file = "aiohttp-3.11.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8fa1510b96c08aaad49303ab11f8803787c99222288f310a62f493faf883ede1"}, - {file = "aiohttp-3.11.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dc065a4285307607df3f3686363e7f8bdd0d8ab35f12226362a847731516e42c"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddb31f8474695cd61fc9455c644fc1606c164b93bff2490390d90464b4655df"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9dec0000d2d8621d8015c293e24589d46fa218637d820894cb7356c77eca3259"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3552fe98e90fdf5918c04769f338a87fa4f00f3b28830ea9b78b1bdc6140e0d"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dfe7f984f28a8ae94ff3a7953cd9678550dbd2a1f9bda5dd9c5ae627744c78e"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a481a574af914b6e84624412666cbfbe531a05667ca197804ecc19c97b8ab1b0"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1987770fb4887560363b0e1a9b75aa303e447433c41284d3af2840a2f226d6e0"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a4ac6a0f0f6402854adca4e3259a623f5c82ec3f0c049374133bcb243132baf9"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c96a43822f1f9f69cc5c3706af33239489a6294be486a0447fb71380070d4d5f"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a5e69046f83c0d3cb8f0d5bd9b8838271b1bc898e01562a04398e160953e8eb9"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:68d54234c8d76d8ef74744f9f9fc6324f1508129e23da8883771cdbb5818cbef"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c9fd9dcf9c91affe71654ef77426f5cf8489305e1c66ed4816f5a21874b094b9"}, - {file = "aiohttp-3.11.12-cp312-cp312-win32.whl", hash = "sha256:0ed49efcd0dc1611378beadbd97beb5d9ca8fe48579fc04a6ed0844072261b6a"}, - {file = "aiohttp-3.11.12-cp312-cp312-win_amd64.whl", hash = "sha256:54775858c7f2f214476773ce785a19ee81d1294a6bedc5cc17225355aab74802"}, - {file = "aiohttp-3.11.12-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:413ad794dccb19453e2b97c2375f2ca3cdf34dc50d18cc2693bd5aed7d16f4b9"}, - {file = "aiohttp-3.11.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4a93d28ed4b4b39e6f46fd240896c29b686b75e39cc6992692e3922ff6982b4c"}, - {file = "aiohttp-3.11.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d589264dbba3b16e8951b6f145d1e6b883094075283dafcab4cdd564a9e353a0"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5148ca8955affdfeb864aca158ecae11030e952b25b3ae15d4e2b5ba299bad2"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:525410e0790aab036492eeea913858989c4cb070ff373ec3bc322d700bdf47c1"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bd8695be2c80b665ae3f05cb584093a1e59c35ecb7d794d1edd96e8cc9201d7"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0203433121484b32646a5f5ea93ae86f3d9559d7243f07e8c0eab5ff8e3f70e"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40cd36749a1035c34ba8d8aaf221b91ca3d111532e5ccb5fa8c3703ab1b967ed"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a7442662afebbf7b4c6d28cb7aab9e9ce3a5df055fc4116cc7228192ad6cb484"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8a2fb742ef378284a50766e985804bd6adb5adb5aa781100b09befdbfa757b65"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2cee3b117a8d13ab98b38d5b6bdcd040cfb4181068d05ce0c474ec9db5f3c5bb"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f6a19bcab7fbd8f8649d6595624856635159a6527861b9cdc3447af288a00c00"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e4cecdb52aaa9994fbed6b81d4568427b6002f0a91c322697a4bfcc2b2363f5a"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:30f546358dfa0953db92ba620101fefc81574f87b2346556b90b5f3ef16e55ce"}, - {file = "aiohttp-3.11.12-cp313-cp313-win32.whl", hash = "sha256:ce1bb21fc7d753b5f8a5d5a4bae99566386b15e716ebdb410154c16c91494d7f"}, - {file = "aiohttp-3.11.12-cp313-cp313-win_amd64.whl", hash = "sha256:f7914ab70d2ee8ab91c13e5402122edbc77821c66d2758abb53aabe87f013287"}, - {file = "aiohttp-3.11.12-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7c3623053b85b4296cd3925eeb725e386644fd5bc67250b3bb08b0f144803e7b"}, - {file = "aiohttp-3.11.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:67453e603cea8e85ed566b2700efa1f6916aefbc0c9fcb2e86aaffc08ec38e78"}, - {file = "aiohttp-3.11.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6130459189e61baac5a88c10019b21e1f0c6d00ebc770e9ce269475650ff7f73"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9060addfa4ff753b09392efe41e6af06ea5dd257829199747b9f15bfad819460"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34245498eeb9ae54c687a07ad7f160053911b5745e186afe2d0c0f2898a1ab8a"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8dc0fba9a74b471c45ca1a3cb6e6913ebfae416678d90529d188886278e7f3f6"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a478aa11b328983c4444dacb947d4513cb371cd323f3845e53caeda6be5589d5"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c160a04283c8c6f55b5bf6d4cad59bb9c5b9c9cd08903841b25f1f7109ef1259"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:edb69b9589324bdc40961cdf0657815df674f1743a8d5ad9ab56a99e4833cfdd"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ee84c2a22a809c4f868153b178fe59e71423e1f3d6a8cd416134bb231fbf6d3"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:bf4480a5438f80e0f1539e15a7eb8b5f97a26fe087e9828e2c0ec2be119a9f72"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:e6b2732ef3bafc759f653a98881b5b9cdef0716d98f013d376ee8dfd7285abf1"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f752e80606b132140883bb262a457c475d219d7163d996dc9072434ffb0784c4"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ab3247d58b393bda5b1c8f31c9edece7162fc13265334217785518dd770792b8"}, - {file = "aiohttp-3.11.12-cp39-cp39-win32.whl", hash = "sha256:0d5176f310a7fe6f65608213cc74f4228e4f4ce9fd10bcb2bb6da8fc66991462"}, - {file = "aiohttp-3.11.12-cp39-cp39-win_amd64.whl", hash = "sha256:74bd573dde27e58c760d9ca8615c41a57e719bff315c9adb6f2a4281a28e8798"}, - {file = "aiohttp-3.11.12.tar.gz", hash = "sha256:7603ca26d75b1b86160ce1bbe2787a0b706e592af5b2504e12caa88a217767b0"}, + {file = "aiohttp-3.11.13-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a4fe27dbbeec445e6e1291e61d61eb212ee9fed6e47998b27de71d70d3e8777d"}, + {file = "aiohttp-3.11.13-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9e64ca2dbea28807f8484c13f684a2f761e69ba2640ec49dacd342763cc265ef"}, + {file = "aiohttp-3.11.13-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9840be675de208d1f68f84d578eaa4d1a36eee70b16ae31ab933520c49ba1325"}, + {file = "aiohttp-3.11.13-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28a772757c9067e2aee8a6b2b425d0efaa628c264d6416d283694c3d86da7689"}, + {file = "aiohttp-3.11.13-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b88aca5adbf4625e11118df45acac29616b425833c3be7a05ef63a6a4017bfdb"}, + {file = "aiohttp-3.11.13-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ce10ddfbe26ed5856d6902162f71b8fe08545380570a885b4ab56aecfdcb07f4"}, + {file = "aiohttp-3.11.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa48dac27f41b36735c807d1ab093a8386701bbf00eb6b89a0f69d9fa26b3671"}, + {file = "aiohttp-3.11.13-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89ce611b1eac93ce2ade68f1470889e0173d606de20c85a012bfa24be96cf867"}, + {file = "aiohttp-3.11.13-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:78e4dd9c34ec7b8b121854eb5342bac8b02aa03075ae8618b6210a06bbb8a115"}, + {file = "aiohttp-3.11.13-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:66047eacbc73e6fe2462b77ce39fc170ab51235caf331e735eae91c95e6a11e4"}, + {file = "aiohttp-3.11.13-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5ad8f1c19fe277eeb8bc45741c6d60ddd11d705c12a4d8ee17546acff98e0802"}, + {file = "aiohttp-3.11.13-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64815c6f02e8506b10113ddbc6b196f58dbef135751cc7c32136df27b736db09"}, + {file = "aiohttp-3.11.13-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:967b93f21b426f23ca37329230d5bd122f25516ae2f24a9cea95a30023ff8283"}, + {file = "aiohttp-3.11.13-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cf1f31f83d16ec344136359001c5e871915c6ab685a3d8dee38e2961b4c81730"}, + {file = "aiohttp-3.11.13-cp310-cp310-win32.whl", hash = "sha256:00c8ac69e259c60976aa2edae3f13d9991cf079aaa4d3cd5a49168ae3748dee3"}, + {file = "aiohttp-3.11.13-cp310-cp310-win_amd64.whl", hash = "sha256:90d571c98d19a8b6e793b34aa4df4cee1e8fe2862d65cc49185a3a3d0a1a3996"}, + {file = "aiohttp-3.11.13-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b35aab22419ba45f8fc290d0010898de7a6ad131e468ffa3922b1b0b24e9d2e"}, + {file = "aiohttp-3.11.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81cba651db8795f688c589dd11a4fbb834f2e59bbf9bb50908be36e416dc760"}, + {file = "aiohttp-3.11.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f55d0f242c2d1fcdf802c8fabcff25a9d85550a4cf3a9cf5f2a6b5742c992839"}, + {file = "aiohttp-3.11.13-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4bea08a6aad9195ac9b1be6b0c7e8a702a9cec57ce6b713698b4a5afa9c2e33"}, + {file = "aiohttp-3.11.13-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6070bcf2173a7146bb9e4735b3c62b2accba459a6eae44deea0eb23e0035a23"}, + {file = "aiohttp-3.11.13-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:718d5deb678bc4b9d575bfe83a59270861417da071ab44542d0fcb6faa686636"}, + {file = "aiohttp-3.11.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f6b2c5b4a4d22b8fb2c92ac98e0747f5f195e8e9448bfb7404cd77e7bfa243f"}, + {file = "aiohttp-3.11.13-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:747ec46290107a490d21fe1ff4183bef8022b848cf9516970cb31de6d9460088"}, + {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:01816f07c9cc9d80f858615b1365f8319d6a5fd079cd668cc58e15aafbc76a54"}, + {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a08ad95fcbd595803e0c4280671d808eb170a64ca3f2980dd38e7a72ed8d1fea"}, + {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c97be90d70f7db3aa041d720bfb95f4869d6063fcdf2bb8333764d97e319b7d0"}, + {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ab915a57c65f7a29353c8014ac4be685c8e4a19e792a79fe133a8e101111438e"}, + {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:35cda4e07f5e058a723436c4d2b7ba2124ab4e0aa49e6325aed5896507a8a42e"}, + {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:af55314407714fe77a68a9ccaab90fdb5deb57342585fd4a3a8102b6d4370080"}, + {file = "aiohttp-3.11.13-cp311-cp311-win32.whl", hash = "sha256:42d689a5c0a0c357018993e471893e939f555e302313d5c61dfc566c2cad6185"}, + {file = "aiohttp-3.11.13-cp311-cp311-win_amd64.whl", hash = "sha256:b73a2b139782a07658fbf170fe4bcdf70fc597fae5ffe75e5b67674c27434a9f"}, + {file = "aiohttp-3.11.13-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2eabb269dc3852537d57589b36d7f7362e57d1ece308842ef44d9830d2dc3c90"}, + {file = "aiohttp-3.11.13-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b77ee42addbb1c36d35aca55e8cc6d0958f8419e458bb70888d8c69a4ca833d"}, + {file = "aiohttp-3.11.13-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55789e93c5ed71832e7fac868167276beadf9877b85697020c46e9a75471f55f"}, + {file = "aiohttp-3.11.13-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c929f9a7249a11e4aa5c157091cfad7f49cc6b13f4eecf9b747104befd9f56f2"}, + {file = "aiohttp-3.11.13-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d33851d85537bbf0f6291ddc97926a754c8f041af759e0aa0230fe939168852b"}, + {file = "aiohttp-3.11.13-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9229d8613bd8401182868fe95688f7581673e1c18ff78855671a4b8284f47bcb"}, + {file = "aiohttp-3.11.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:669dd33f028e54fe4c96576f406ebb242ba534dd3a981ce009961bf49960f117"}, + {file = "aiohttp-3.11.13-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c1b20a1ace54af7db1f95af85da530fe97407d9063b7aaf9ce6a32f44730778"}, + {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5724cc77f4e648362ebbb49bdecb9e2b86d9b172c68a295263fa072e679ee69d"}, + {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:aa36c35e94ecdb478246dd60db12aba57cfcd0abcad43c927a8876f25734d496"}, + {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9b5b37c863ad5b0892cc7a4ceb1e435e5e6acd3f2f8d3e11fa56f08d3c67b820"}, + {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e06cf4852ce8c4442a59bae5a3ea01162b8fcb49ab438d8548b8dc79375dad8a"}, + {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5194143927e494616e335d074e77a5dac7cd353a04755330c9adc984ac5a628e"}, + {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:afcb6b275c2d2ba5d8418bf30a9654fa978b4f819c2e8db6311b3525c86fe637"}, + {file = "aiohttp-3.11.13-cp312-cp312-win32.whl", hash = "sha256:7104d5b3943c6351d1ad7027d90bdd0ea002903e9f610735ac99df3b81f102ee"}, + {file = "aiohttp-3.11.13-cp312-cp312-win_amd64.whl", hash = "sha256:47dc018b1b220c48089b5b9382fbab94db35bef2fa192995be22cbad3c5730c8"}, + {file = "aiohttp-3.11.13-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9862d077b9ffa015dbe3ce6c081bdf35135948cb89116e26667dd183550833d1"}, + {file = "aiohttp-3.11.13-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fbfef0666ae9e07abfa2c54c212ac18a1f63e13e0760a769f70b5717742f3ece"}, + {file = "aiohttp-3.11.13-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:93a1f7d857c4fcf7cabb1178058182c789b30d85de379e04f64c15b7e88d66fb"}, + {file = "aiohttp-3.11.13-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba40b7ae0f81c7029583a338853f6607b6d83a341a3dcde8bed1ea58a3af1df9"}, + {file = "aiohttp-3.11.13-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5b95787335c483cd5f29577f42bbe027a412c5431f2f80a749c80d040f7ca9f"}, + {file = "aiohttp-3.11.13-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7d474c5c1f0b9405c1565fafdc4429fa7d986ccbec7ce55bc6a330f36409cad"}, + {file = "aiohttp-3.11.13-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e83fb1991e9d8982b3b36aea1e7ad27ea0ce18c14d054c7a404d68b0319eebb"}, + {file = "aiohttp-3.11.13-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4586a68730bd2f2b04a83e83f79d271d8ed13763f64b75920f18a3a677b9a7f0"}, + {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fe4eb0e7f50cdb99b26250d9328faef30b1175a5dbcfd6d0578d18456bac567"}, + {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2a8a6bc19818ac3e5596310ace5aa50d918e1ebdcc204dc96e2f4d505d51740c"}, + {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7f27eec42f6c3c1df09cfc1f6786308f8b525b8efaaf6d6bd76c1f52c6511f6a"}, + {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:2a4a13dfbb23977a51853b419141cd0a9b9573ab8d3a1455c6e63561387b52ff"}, + {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:02876bf2f69b062584965507b07bc06903c2dc93c57a554b64e012d636952654"}, + {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b992778d95b60a21c4d8d4a5f15aaab2bd3c3e16466a72d7f9bfd86e8cea0d4b"}, + {file = "aiohttp-3.11.13-cp313-cp313-win32.whl", hash = "sha256:507ab05d90586dacb4f26a001c3abf912eb719d05635cbfad930bdbeb469b36c"}, + {file = "aiohttp-3.11.13-cp313-cp313-win_amd64.whl", hash = "sha256:5ceb81a4db2decdfa087381b5fc5847aa448244f973e5da232610304e199e7b2"}, + {file = "aiohttp-3.11.13-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:51c3ff9c7a25f3cad5c09d9aacbc5aefb9267167c4652c1eb737989b554fe278"}, + {file = "aiohttp-3.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e271beb2b1dabec5cd84eb488bdabf9758d22ad13471e9c356be07ad139b3012"}, + {file = "aiohttp-3.11.13-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0e9eb7e5764abcb49f0e2bd8f5731849b8728efbf26d0cac8e81384c95acec3f"}, + {file = "aiohttp-3.11.13-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baae005092e3f200de02699314ac8933ec20abf998ec0be39448f6605bce93df"}, + {file = "aiohttp-3.11.13-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1982c98ac62c132d2b773d50e2fcc941eb0b8bad3ec078ce7e7877c4d5a2dce7"}, + {file = "aiohttp-3.11.13-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2b25b2eeb35707113b2d570cadc7c612a57f1c5d3e7bb2b13870fe284e08fc0"}, + {file = "aiohttp-3.11.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b27961d65639128336b7a7c3f0046dcc62a9443d5ef962e3c84170ac620cec47"}, + {file = "aiohttp-3.11.13-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a01fe9f1e05025eacdd97590895e2737b9f851d0eb2e017ae9574d9a4f0b6252"}, + {file = "aiohttp-3.11.13-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa1fb1b61881c8405829c50e9cc5c875bfdbf685edf57a76817dfb50643e4a1a"}, + {file = "aiohttp-3.11.13-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:25de43bb3cf83ad83efc8295af7310219af6dbe4c543c2e74988d8e9c8a2a917"}, + {file = "aiohttp-3.11.13-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fe7065e2215e4bba63dc00db9ae654c1ba3950a5fff691475a32f511142fcddb"}, + {file = "aiohttp-3.11.13-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:7836587eef675a17d835ec3d98a8c9acdbeb2c1d72b0556f0edf4e855a25e9c1"}, + {file = "aiohttp-3.11.13-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:85fa0b18558eb1427090912bd456a01f71edab0872f4e0f9e4285571941e4090"}, + {file = "aiohttp-3.11.13-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a86dc177eb4c286c19d1823ac296299f59ed8106c9536d2b559f65836e0fb2c6"}, + {file = "aiohttp-3.11.13-cp39-cp39-win32.whl", hash = "sha256:684eea71ab6e8ade86b9021bb62af4bf0881f6be4e926b6b5455de74e420783a"}, + {file = "aiohttp-3.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:82c249f2bfa5ecbe4a1a7902c81c0fba52ed9ebd0176ab3047395d02ad96cfcb"}, + {file = "aiohttp-3.11.13.tar.gz", hash = "sha256:8ce789231404ca8fff7f693cdce398abf6d90fd5dae2b1847477196c243b1fbb"}, ] [package.dependencies] @@ -227,21 +227,21 @@ files = [ [[package]] name = "attrs" -version = "24.3.0" +version = "25.3.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"}, - {file = "attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff"}, + {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, + {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, ] [package.extras] benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] @@ -281,14 +281,14 @@ dev = ["base58", "mypy", "pylint", "pytest", "pytest-cov"] [[package]] name = "cachetools" -version = "5.5.1" +version = "5.5.2" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "cachetools-5.5.1-py3-none-any.whl", hash = "sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb"}, - {file = "cachetools-5.5.1.tar.gz", hash = "sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95"}, + {file = "cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a"}, + {file = "cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4"}, ] [[package]] @@ -305,14 +305,14 @@ files = [ [[package]] name = "certifi" -version = "2024.12.14" +version = "2025.1.31" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" groups = ["main"] files = [ - {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, - {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, + {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, + {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, ] [[package]] @@ -540,74 +540,75 @@ yaml = ["PyYAML"] [[package]] name = "coverage" -version = "7.6.10" +version = "7.6.12" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "coverage-7.6.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78"}, - {file = "coverage-7.6.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c"}, - {file = "coverage-7.6.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3b204c11e2b2d883946fe1d97f89403aa1811df28ce0447439178cc7463448a"}, - {file = "coverage-7.6.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32ee6d8491fcfc82652a37109f69dee9a830e9379166cb73c16d8dc5c2915165"}, - {file = "coverage-7.6.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675cefc4c06e3b4c876b85bfb7c59c5e2218167bbd4da5075cbe3b5790a28988"}, - {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f4f620668dbc6f5e909a0946a877310fb3d57aea8198bde792aae369ee1c23b5"}, - {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4eea95ef275de7abaef630c9b2c002ffbc01918b726a39f5a4353916ec72d2f3"}, - {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e2f0280519e42b0a17550072861e0bc8a80a0870de260f9796157d3fca2733c5"}, - {file = "coverage-7.6.10-cp310-cp310-win32.whl", hash = "sha256:bc67deb76bc3717f22e765ab3e07ee9c7a5e26b9019ca19a3b063d9f4b874244"}, - {file = "coverage-7.6.10-cp310-cp310-win_amd64.whl", hash = "sha256:0f460286cb94036455e703c66988851d970fdfd8acc2a1122ab7f4f904e4029e"}, - {file = "coverage-7.6.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ea3c8f04b3e4af80e17bab607c386a830ffc2fb88a5484e1df756478cf70d1d3"}, - {file = "coverage-7.6.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:507a20fc863cae1d5720797761b42d2d87a04b3e5aeb682ef3b7332e90598f43"}, - {file = "coverage-7.6.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132"}, - {file = "coverage-7.6.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f"}, - {file = "coverage-7.6.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994"}, - {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99"}, - {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd"}, - {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377"}, - {file = "coverage-7.6.10-cp311-cp311-win32.whl", hash = "sha256:299e91b274c5c9cdb64cbdf1b3e4a8fe538a7a86acdd08fae52301b28ba297f8"}, - {file = "coverage-7.6.10-cp311-cp311-win_amd64.whl", hash = "sha256:489a01f94aa581dbd961f306e37d75d4ba16104bbfa2b0edb21d29b73be83609"}, - {file = "coverage-7.6.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853"}, - {file = "coverage-7.6.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078"}, - {file = "coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0"}, - {file = "coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50"}, - {file = "coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022"}, - {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b"}, - {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0"}, - {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852"}, - {file = "coverage-7.6.10-cp312-cp312-win32.whl", hash = "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359"}, - {file = "coverage-7.6.10-cp312-cp312-win_amd64.whl", hash = "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247"}, - {file = "coverage-7.6.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9"}, - {file = "coverage-7.6.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b"}, - {file = "coverage-7.6.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690"}, - {file = "coverage-7.6.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18"}, - {file = "coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c"}, - {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd"}, - {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e"}, - {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694"}, - {file = "coverage-7.6.10-cp313-cp313-win32.whl", hash = "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6"}, - {file = "coverage-7.6.10-cp313-cp313-win_amd64.whl", hash = "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e"}, - {file = "coverage-7.6.10-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe"}, - {file = "coverage-7.6.10-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273"}, - {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8"}, - {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098"}, - {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb"}, - {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0"}, - {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf"}, - {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2"}, - {file = "coverage-7.6.10-cp313-cp313t-win32.whl", hash = "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312"}, - {file = "coverage-7.6.10-cp313-cp313t-win_amd64.whl", hash = "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d"}, - {file = "coverage-7.6.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:656c82b8a0ead8bba147de9a89bda95064874c91a3ed43a00e687f23cc19d53a"}, - {file = "coverage-7.6.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccc2b70a7ed475c68ceb548bf69cec1e27305c1c2606a5eb7c3afff56a1b3b27"}, - {file = "coverage-7.6.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5e37dc41d57ceba70956fa2fc5b63c26dba863c946ace9705f8eca99daecdc4"}, - {file = "coverage-7.6.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0aa9692b4fdd83a4647eeb7db46410ea1322b5ed94cd1715ef09d1d5922ba87f"}, - {file = "coverage-7.6.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa744da1820678b475e4ba3dfd994c321c5b13381d1041fe9c608620e6676e25"}, - {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c0b1818063dc9e9d838c09e3a473c1422f517889436dd980f5d721899e66f315"}, - {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:59af35558ba08b758aec4d56182b222976330ef8d2feacbb93964f576a7e7a90"}, - {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7ed2f37cfce1ce101e6dffdfd1c99e729dd2ffc291d02d3e2d0af8b53d13840d"}, - {file = "coverage-7.6.10-cp39-cp39-win32.whl", hash = "sha256:4bcc276261505d82f0ad426870c3b12cb177752834a633e737ec5ee79bbdff18"}, - {file = "coverage-7.6.10-cp39-cp39-win_amd64.whl", hash = "sha256:457574f4599d2b00f7f637a0700a6422243b3565509457b2dbd3f50703e11f59"}, - {file = "coverage-7.6.10-pp39.pp310-none-any.whl", hash = "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f"}, - {file = "coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23"}, + {file = "coverage-7.6.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8"}, + {file = "coverage-7.6.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06097c7abfa611c91edb9e6920264e5be1d6ceb374efb4986f38b09eed4cb2fe"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:220fa6c0ad7d9caef57f2c8771918324563ef0d8272c94974717c3909664e674"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3688b99604a24492bcfe1c106278c45586eb819bf66a654d8a9a1433022fb2eb"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1a987778b9c71da2fc8948e6f2656da6ef68f59298b7e9786849634c35d2c3c"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cec6b9ce3bd2b7853d4a4563801292bfee40b030c05a3d29555fd2a8ee9bd68c"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ace9048de91293e467b44bce0f0381345078389814ff6e18dbac8fdbf896360e"}, + {file = "coverage-7.6.12-cp310-cp310-win32.whl", hash = "sha256:ea31689f05043d520113e0552f039603c4dd71fa4c287b64cb3606140c66f425"}, + {file = "coverage-7.6.12-cp310-cp310-win_amd64.whl", hash = "sha256:676f92141e3c5492d2a1596d52287d0d963df21bf5e55c8b03075a60e1ddf8aa"}, + {file = "coverage-7.6.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015"}, + {file = "coverage-7.6.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba"}, + {file = "coverage-7.6.12-cp311-cp311-win32.whl", hash = "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f"}, + {file = "coverage-7.6.12-cp311-cp311-win_amd64.whl", hash = "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558"}, + {file = "coverage-7.6.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad"}, + {file = "coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a"}, + {file = "coverage-7.6.12-cp312-cp312-win32.whl", hash = "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95"}, + {file = "coverage-7.6.12-cp312-cp312-win_amd64.whl", hash = "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288"}, + {file = "coverage-7.6.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:488c27b3db0ebee97a830e6b5a3ea930c4a6e2c07f27a5e67e1b3532e76b9ef1"}, + {file = "coverage-7.6.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d1095bbee1851269f79fd8e0c9b5544e4c00c0c24965e66d8cba2eb5bb535fd"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0533adc29adf6a69c1baa88c3d7dbcaadcffa21afbed3ca7a225a440e4744bf9"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53c56358d470fa507a2b6e67a68fd002364d23c83741dbc4c2e0680d80ca227e"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cbb1a3027c79ca6310bf101014614f6e6e18c226474606cf725238cf5bc2d4"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79cac3390bfa9836bb795be377395f28410811c9066bc4eefd8015258a7578c6"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b148068e881faa26d878ff63e79650e208e95cf1c22bd3f77c3ca7b1d9821a3"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8bec2ac5da793c2685ce5319ca9bcf4eee683b8a1679051f8e6ec04c4f2fd7dc"}, + {file = "coverage-7.6.12-cp313-cp313-win32.whl", hash = "sha256:200e10beb6ddd7c3ded322a4186313d5ca9e63e33d8fab4faa67ef46d3460af3"}, + {file = "coverage-7.6.12-cp313-cp313-win_amd64.whl", hash = "sha256:2b996819ced9f7dbb812c701485d58f261bef08f9b85304d41219b1496b591ef"}, + {file = "coverage-7.6.12-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:299cf973a7abff87a30609879c10df0b3bfc33d021e1adabc29138a48888841e"}, + {file = "coverage-7.6.12-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b467a8c56974bf06e543e69ad803c6865249d7a5ccf6980457ed2bc50312703"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2458f275944db8129f95d91aee32c828a408481ecde3b30af31d552c2ce284a0"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a9d8be07fb0832636a0f72b80d2a652fe665e80e720301fb22b191c3434d924"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d47376a4f445e9743f6c83291e60adb1b127607a3618e3185bbc8091f0467b"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b95574d06aa9d2bd6e5cc35a5bbe35696342c96760b69dc4287dbd5abd4ad51d"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ecea0c38c9079570163d663c0433a9af4094a60aafdca491c6a3d248c7432827"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2251fabcfee0a55a8578a9d29cecfee5f2de02f11530e7d5c5a05859aa85aee9"}, + {file = "coverage-7.6.12-cp313-cp313t-win32.whl", hash = "sha256:eb5507795caabd9b2ae3f1adc95f67b1104971c22c624bb354232d65c4fc90b3"}, + {file = "coverage-7.6.12-cp313-cp313t-win_amd64.whl", hash = "sha256:f60a297c3987c6c02ffb29effc70eadcbb412fe76947d394a1091a3615948e2f"}, + {file = "coverage-7.6.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e7575ab65ca8399c8c4f9a7d61bbd2d204c8b8e447aab9d355682205c9dd948d"}, + {file = "coverage-7.6.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8161d9fbc7e9fe2326de89cd0abb9f3599bccc1287db0aba285cb68d204ce929"}, + {file = "coverage-7.6.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a1e465f398c713f1b212400b4e79a09829cd42aebd360362cd89c5bdc44eb87"}, + {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f25d8b92a4e31ff1bd873654ec367ae811b3a943583e05432ea29264782dc32c"}, + {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a936309a65cc5ca80fa9f20a442ff9e2d06927ec9a4f54bcba9c14c066323f2"}, + {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aa6f302a3a0b5f240ee201297fff0bbfe2fa0d415a94aeb257d8b461032389bd"}, + {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f973643ef532d4f9be71dd88cf7588936685fdb576d93a79fe9f65bc337d9d73"}, + {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:78f5243bb6b1060aed6213d5107744c19f9571ec76d54c99cc15938eb69e0e86"}, + {file = "coverage-7.6.12-cp39-cp39-win32.whl", hash = "sha256:69e62c5034291c845fc4df7f8155e8544178b6c774f97a99e2734b05eb5bed31"}, + {file = "coverage-7.6.12-cp39-cp39-win_amd64.whl", hash = "sha256:b01a840ecc25dce235ae4c1b6a0daefb2a203dba0e6e980637ee9c2f6ee0df57"}, + {file = "coverage-7.6.12-pp39.pp310-none-any.whl", hash = "sha256:7e39e845c4d764208e7b8f6a21c541ade741e2c41afabdfa1caa28687a3c98cf"}, + {file = "coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953"}, + {file = "coverage-7.6.12.tar.gz", hash = "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2"}, ] [package.extras] @@ -615,41 +616,47 @@ toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cryptography" -version = "44.0.0" +version = "44.0.2" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.7" groups = ["main"] files = [ - {file = "cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123"}, - {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092"}, - {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f"}, - {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb"}, - {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b"}, - {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543"}, - {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:60eb32934076fa07e4316b7b2742fa52cbb190b42c2df2863dbc4230a0a9b385"}, - {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e"}, - {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e"}, - {file = "cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053"}, - {file = "cryptography-44.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd"}, - {file = "cryptography-44.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591"}, - {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7"}, - {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc"}, - {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289"}, - {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7"}, - {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c"}, - {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9abcc2e083cbe8dde89124a47e5e53ec38751f0d7dfd36801008f316a127d7ba"}, - {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64"}, - {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285"}, - {file = "cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417"}, - {file = "cryptography-44.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede"}, - {file = "cryptography-44.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731"}, - {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4"}, - {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756"}, - {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c"}, - {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa"}, - {file = "cryptography-44.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c"}, - {file = "cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02"}, + {file = "cryptography-44.0.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:efcfe97d1b3c79e486554efddeb8f6f53a4cdd4cf6086642784fa31fc384e1d7"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29ecec49f3ba3f3849362854b7253a9f59799e3763b0c9d0826259a88efa02f1"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc821e161ae88bfe8088d11bb39caf2916562e0a2dc7b6d56714a48b784ef0bb"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3c00b6b757b32ce0f62c574b78b939afab9eecaf597c4d624caca4f9e71e7843"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7bdcd82189759aba3816d1f729ce42ffded1ac304c151d0a8e89b9996ab863d5"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:4973da6ca3db4405c54cd0b26d328be54c7747e89e284fcff166132eb7bccc9c"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4e389622b6927d8133f314949a9812972711a111d577a5d1f4bee5e58736b80a"}, + {file = "cryptography-44.0.2-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f514ef4cd14bb6fb484b4a60203e912cfcb64f2ab139e88c2274511514bf7308"}, + {file = "cryptography-44.0.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1bc312dfb7a6e5d66082c87c34c8a62176e684b6fe3d90fcfe1568de675e6688"}, + {file = "cryptography-44.0.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b721b8b4d948b218c88cb8c45a01793483821e709afe5f622861fc6182b20a7"}, + {file = "cryptography-44.0.2-cp37-abi3-win32.whl", hash = "sha256:51e4de3af4ec3899d6d178a8c005226491c27c4ba84101bfb59c901e10ca9f79"}, + {file = "cryptography-44.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:c505d61b6176aaf982c5717ce04e87da5abc9a36a5b39ac03905c4aafe8de7aa"}, + {file = "cryptography-44.0.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8e0ddd63e6bf1161800592c71ac794d3fb8001f2caebe0966e77c5234fa9efc3"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81276f0ea79a208d961c433a947029e1a15948966658cf6710bbabb60fcc2639"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a1e657c0f4ea2a23304ee3f964db058c9e9e635cc7019c4aa21c330755ef6fd"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6210c05941994290f3f7f175a4a57dbbb2afd9273657614c506d5976db061181"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1c3572526997b36f245a96a2b1713bf79ce99b271bbcf084beb6b9b075f29ea"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b042d2a275c8cee83a4b7ae30c45a15e6a4baa65a179a0ec2d78ebb90e4f6699"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:d03806036b4f89e3b13b6218fefea8d5312e450935b1a2d55f0524e2ed7c59d9"}, + {file = "cryptography-44.0.2-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c7362add18b416b69d58c910caa217f980c5ef39b23a38a0880dfd87bdf8cd23"}, + {file = "cryptography-44.0.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8cadc6e3b5a1f144a039ea08a0bdb03a2a92e19c46be3285123d32029f40a922"}, + {file = "cryptography-44.0.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6f101b1f780f7fc613d040ca4bdf835c6ef3b00e9bd7125a4255ec574c7916e4"}, + {file = "cryptography-44.0.2-cp39-abi3-win32.whl", hash = "sha256:3dc62975e31617badc19a906481deacdeb80b4bb454394b4098e3f2525a488c5"}, + {file = "cryptography-44.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:5f6f90b72d8ccadb9c6e311c775c8305381db88374c65fa1a68250aa8a9cb3a6"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:af4ff3e388f2fa7bff9f7f2b31b87d5651c45731d3e8cfa0944be43dff5cfbdb"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:0529b1d5a0105dd3731fa65680b45ce49da4d8115ea76e9da77a875396727b41"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7ca25849404be2f8e4b3c59483d9d3c51298a22c1c61a0e84415104dacaf5562"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:268e4e9b177c76d569e8a145a6939eca9a5fec658c932348598818acf31ae9a5"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:9eb9d22b0a5d8fd9925a7764a054dca914000607dff201a24c791ff5c799e1fa"}, + {file = "cryptography-44.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2bf7bf75f7df9715f810d1b038870309342bff3069c5bd8c6b96128cb158668d"}, + {file = "cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:909c97ab43a9c0c0b0ada7a1281430e4e5ec0458e6d9244c0e821bbf152f061d"}, + {file = "cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:96e7a5e9d6e71f9f4fca8eebfd603f8e86c5225bb18eb621b2c1e50b290a9471"}, + {file = "cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d1b3031093a366ac767b3feb8bcddb596671b3aaff82d4050f984da0c248b615"}, + {file = "cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:04abd71114848aa25edb28e225ab5f268096f44cf0127f3d36975bdf1bdf3390"}, + {file = "cryptography-44.0.2.tar.gz", hash = "sha256:c63454aa261a0cf0c5b4718349629793e9e634993538db841165b3df74f37ec0"}, ] [package.dependencies] @@ -662,7 +669,7 @@ nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_version >= \"3.8\""] pep8test = ["check-sdist ; python_version >= \"3.8\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi (>=2024)", "cryptography-vectors (==44.0.0)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test = ["certifi (>=2024)", "cryptography-vectors (==44.0.2)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] test-randomorder = ["pytest-randomly"] [[package]] @@ -784,38 +791,38 @@ cython = ["cython"] [[package]] name = "debugpy" -version = "1.8.12" +version = "1.8.13" description = "An implementation of the Debug Adapter Protocol for Python" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "debugpy-1.8.12-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:a2ba7ffe58efeae5b8fad1165357edfe01464f9aef25e814e891ec690e7dd82a"}, - {file = "debugpy-1.8.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbbd4149c4fc5e7d508ece083e78c17442ee13b0e69bfa6bd63003e486770f45"}, - {file = "debugpy-1.8.12-cp310-cp310-win32.whl", hash = "sha256:b202f591204023b3ce62ff9a47baa555dc00bb092219abf5caf0e3718ac20e7c"}, - {file = "debugpy-1.8.12-cp310-cp310-win_amd64.whl", hash = "sha256:9649eced17a98ce816756ce50433b2dd85dfa7bc92ceb60579d68c053f98dff9"}, - {file = "debugpy-1.8.12-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:36f4829839ef0afdfdd208bb54f4c3d0eea86106d719811681a8627ae2e53dd5"}, - {file = "debugpy-1.8.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a28ed481d530e3138553be60991d2d61103ce6da254e51547b79549675f539b7"}, - {file = "debugpy-1.8.12-cp311-cp311-win32.whl", hash = "sha256:4ad9a94d8f5c9b954e0e3b137cc64ef3f579d0df3c3698fe9c3734ee397e4abb"}, - {file = "debugpy-1.8.12-cp311-cp311-win_amd64.whl", hash = "sha256:4703575b78dd697b294f8c65588dc86874ed787b7348c65da70cfc885efdf1e1"}, - {file = "debugpy-1.8.12-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:7e94b643b19e8feb5215fa508aee531387494bf668b2eca27fa769ea11d9f498"}, - {file = "debugpy-1.8.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:086b32e233e89a2740c1615c2f775c34ae951508b28b308681dbbb87bba97d06"}, - {file = "debugpy-1.8.12-cp312-cp312-win32.whl", hash = "sha256:2ae5df899732a6051b49ea2632a9ea67f929604fd2b036613a9f12bc3163b92d"}, - {file = "debugpy-1.8.12-cp312-cp312-win_amd64.whl", hash = "sha256:39dfbb6fa09f12fae32639e3286112fc35ae976114f1f3d37375f3130a820969"}, - {file = "debugpy-1.8.12-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:696d8ae4dff4cbd06bf6b10d671e088b66669f110c7c4e18a44c43cf75ce966f"}, - {file = "debugpy-1.8.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:898fba72b81a654e74412a67c7e0a81e89723cfe2a3ea6fcd3feaa3395138ca9"}, - {file = "debugpy-1.8.12-cp313-cp313-win32.whl", hash = "sha256:22a11c493c70413a01ed03f01c3c3a2fc4478fc6ee186e340487b2edcd6f4180"}, - {file = "debugpy-1.8.12-cp313-cp313-win_amd64.whl", hash = "sha256:fdb3c6d342825ea10b90e43d7f20f01535a72b3a1997850c0c3cefa5c27a4a2c"}, - {file = "debugpy-1.8.12-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:b0232cd42506d0c94f9328aaf0d1d0785f90f87ae72d9759df7e5051be039738"}, - {file = "debugpy-1.8.12-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9af40506a59450f1315168d47a970db1a65aaab5df3833ac389d2899a5d63b3f"}, - {file = "debugpy-1.8.12-cp38-cp38-win32.whl", hash = "sha256:5cc45235fefac57f52680902b7d197fb2f3650112379a6fa9aa1b1c1d3ed3f02"}, - {file = "debugpy-1.8.12-cp38-cp38-win_amd64.whl", hash = "sha256:557cc55b51ab2f3371e238804ffc8510b6ef087673303890f57a24195d096e61"}, - {file = "debugpy-1.8.12-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:b5c6c967d02fee30e157ab5227706f965d5c37679c687b1e7bbc5d9e7128bd41"}, - {file = "debugpy-1.8.12-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88a77f422f31f170c4b7e9ca58eae2a6c8e04da54121900651dfa8e66c29901a"}, - {file = "debugpy-1.8.12-cp39-cp39-win32.whl", hash = "sha256:a4042edef80364239f5b7b5764e55fd3ffd40c32cf6753da9bda4ff0ac466018"}, - {file = "debugpy-1.8.12-cp39-cp39-win_amd64.whl", hash = "sha256:f30b03b0f27608a0b26c75f0bb8a880c752c0e0b01090551b9d87c7d783e2069"}, - {file = "debugpy-1.8.12-py2.py3-none-any.whl", hash = "sha256:274b6a2040349b5c9864e475284bce5bb062e63dce368a394b8cc865ae3b00c6"}, - {file = "debugpy-1.8.12.tar.gz", hash = "sha256:646530b04f45c830ceae8e491ca1c9320a2d2f0efea3141487c82130aba70dce"}, + {file = "debugpy-1.8.13-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:06859f68e817966723ffe046b896b1bd75c665996a77313370336ee9e1de3e90"}, + {file = "debugpy-1.8.13-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb56c2db69fb8df3168bc857d7b7d2494fed295dfdbde9a45f27b4b152f37520"}, + {file = "debugpy-1.8.13-cp310-cp310-win32.whl", hash = "sha256:46abe0b821cad751fc1fb9f860fb2e68d75e2c5d360986d0136cd1db8cad4428"}, + {file = "debugpy-1.8.13-cp310-cp310-win_amd64.whl", hash = "sha256:dc7b77f5d32674686a5f06955e4b18c0e41fb5a605f5b33cf225790f114cfeec"}, + {file = "debugpy-1.8.13-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:eee02b2ed52a563126c97bf04194af48f2fe1f68bb522a312b05935798e922ff"}, + {file = "debugpy-1.8.13-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4caca674206e97c85c034c1efab4483f33971d4e02e73081265ecb612af65377"}, + {file = "debugpy-1.8.13-cp311-cp311-win32.whl", hash = "sha256:7d9a05efc6973b5aaf076d779cf3a6bbb1199e059a17738a2aa9d27a53bcc888"}, + {file = "debugpy-1.8.13-cp311-cp311-win_amd64.whl", hash = "sha256:62f9b4a861c256f37e163ada8cf5a81f4c8d5148fc17ee31fb46813bd658cdcc"}, + {file = "debugpy-1.8.13-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:2b8de94c5c78aa0d0ed79023eb27c7c56a64c68217d881bee2ffbcb13951d0c1"}, + {file = "debugpy-1.8.13-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887d54276cefbe7290a754424b077e41efa405a3e07122d8897de54709dbe522"}, + {file = "debugpy-1.8.13-cp312-cp312-win32.whl", hash = "sha256:3872ce5453b17837ef47fb9f3edc25085ff998ce63543f45ba7af41e7f7d370f"}, + {file = "debugpy-1.8.13-cp312-cp312-win_amd64.whl", hash = "sha256:63ca7670563c320503fea26ac688988d9d6b9c6a12abc8a8cf2e7dd8e5f6b6ea"}, + {file = "debugpy-1.8.13-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:31abc9618be4edad0b3e3a85277bc9ab51a2d9f708ead0d99ffb5bb750e18503"}, + {file = "debugpy-1.8.13-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0bd87557f97bced5513a74088af0b84982b6ccb2e254b9312e29e8a5c4270eb"}, + {file = "debugpy-1.8.13-cp313-cp313-win32.whl", hash = "sha256:5268ae7fdca75f526d04465931cb0bd24577477ff50e8bb03dab90983f4ebd02"}, + {file = "debugpy-1.8.13-cp313-cp313-win_amd64.whl", hash = "sha256:79ce4ed40966c4c1631d0131606b055a5a2f8e430e3f7bf8fd3744b09943e8e8"}, + {file = "debugpy-1.8.13-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:acf39a6e98630959763f9669feddee540745dfc45ad28dbc9bd1f9cd60639391"}, + {file = "debugpy-1.8.13-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:924464d87e7d905eb0d79fb70846558910e906d9ee309b60c4fe597a2e802590"}, + {file = "debugpy-1.8.13-cp38-cp38-win32.whl", hash = "sha256:3dae443739c6b604802da9f3e09b0f45ddf1cf23c99161f3a1a8039f61a8bb89"}, + {file = "debugpy-1.8.13-cp38-cp38-win_amd64.whl", hash = "sha256:ed93c3155fc1f888ab2b43626182174e457fc31b7781cd1845629303790b8ad1"}, + {file = "debugpy-1.8.13-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:6fab771639332bd8ceb769aacf454a30d14d7a964f2012bf9c4e04c60f16e85b"}, + {file = "debugpy-1.8.13-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32b6857f8263a969ce2ca098f228e5cc0604d277447ec05911a8c46cf3e7e307"}, + {file = "debugpy-1.8.13-cp39-cp39-win32.whl", hash = "sha256:f14d2c4efa1809da125ca62df41050d9c7cd9cb9e380a2685d1e453c4d450ccb"}, + {file = "debugpy-1.8.13-cp39-cp39-win_amd64.whl", hash = "sha256:ea869fe405880327497e6945c09365922c79d2a1eed4c3ae04d77ac7ae34b2b5"}, + {file = "debugpy-1.8.13-py2.py3-none-any.whl", hash = "sha256:d4ba115cdd0e3a70942bd562adba9ec8c651fe69ddde2298a1be296fc331906f"}, + {file = "debugpy-1.8.13.tar.gz", hash = "sha256:837e7bef95bdefba426ae38b9a94821ebdc5bea55627879cd48165c90b9e50ce"}, ] [[package]] @@ -868,10 +875,12 @@ name = "did-webvh" version = "0.3.0" description = "This repository includes Python libraries for working with `did:webvh` (did:web + Verified History) DID documents and the underlying log format." optional = false -python-versions = ">= 3.10, <4" +python-versions = "<4,>=3.10" groups = ["main"] -files = [] -develop = false +files = [ + {file = "did_webvh-0.3.0-py3-none-any.whl", hash = "sha256:30a6b80e27a47631efc1ebd8b1731dce72230a279499f235a4d53ae72ac06d7c"}, + {file = "did_webvh-0.3.0.tar.gz", hash = "sha256:e71390280f2276651a40f18bb2a3cd8939de30a1d53f247536c539f80eb64fb5"}, +] [package.dependencies] aiohttp = ">=3.10.5,<4.0.0" @@ -880,12 +889,6 @@ base58 = ">=2.1.0,<2.2.0" jsoncanon = ">=0.2.3,<0.3.0" multiformats = ">=0.3.1,<0.4.0" -[package.source] -type = "git" -url = "https://github.com/decentralized-identity/didwebvh-py.git" -reference = "HEAD" -resolved_reference = "2ac2b83d5626aaa55307104558a296be41b6528a" - [[package]] name = "didcomm-messaging" version = "0.1.1" @@ -923,14 +926,14 @@ files = [ [[package]] name = "ecdsa" -version = "0.19.0" +version = "0.19.1" description = "ECDSA cryptographic signature library (pure python)" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.6" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.6" groups = ["main"] files = [ - {file = "ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a"}, - {file = "ecdsa-0.19.0.tar.gz", hash = "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8"}, + {file = "ecdsa-0.19.1-py2.py3-none-any.whl", hash = "sha256:30638e27cf77b7e15c4c4cc1973720149e1033827cfd00661ca5c8cc0cdb24c3"}, + {file = "ecdsa-0.19.1.tar.gz", hash = "sha256:478cba7b62555866fcb3bb3fe985e06decbdb68ef55713c4e5ab98c57d508e61"}, ] [package.dependencies] @@ -961,14 +964,14 @@ test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "eth-typing" -version = "5.1.0" +version = "5.2.0" description = "eth-typing: Common type annotations for ethereum python packages" optional = false python-versions = "<4,>=3.8" groups = ["main"] files = [ - {file = "eth_typing-5.1.0-py3-none-any.whl", hash = "sha256:c0d6b93f5385aa84efc4b47ae2bd478da069bc0ffda8b67e0ccb573f43defd29"}, - {file = "eth_typing-5.1.0.tar.gz", hash = "sha256:8581f212ee6252aaa285377a77620f6e5f6e16ac3f144c61f098fafd47967b1a"}, + {file = "eth_typing-5.2.0-py3-none-any.whl", hash = "sha256:e1f424e97990fc3c6a1c05a7b0968caed4e20e9c99a4d5f4db3df418e25ddc80"}, + {file = "eth_typing-5.2.0.tar.gz", hash = "sha256:28685f7e2270ea0d209b75bdef76d8ecef27703e1a16399f6929820d05071c28"}, ] [package.dependencies] @@ -1019,14 +1022,14 @@ testing = ["hatch", "pre-commit", "pytest", "tox"] [[package]] name = "filelock" -version = "3.17.0" +version = "3.18.0" description = "A platform independent file lock." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "filelock-3.17.0-py3-none-any.whl", hash = "sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338"}, - {file = "filelock-3.17.0.tar.gz", hash = "sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e"}, + {file = "filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de"}, + {file = "filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2"}, ] [package.extras] @@ -1187,14 +1190,14 @@ files = [ [[package]] name = "identify" -version = "2.6.6" +version = "2.6.9" description = "File identification library for Python" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "identify-2.6.6-py2.py3-none-any.whl", hash = "sha256:cbd1810bce79f8b671ecb20f53ee0ae8e86ae84b557de31d89709dc2a48ba881"}, - {file = "identify-2.6.6.tar.gz", hash = "sha256:7bec12768ed44ea4761efb47806f0a41f86e7c0a5fdf5950d4648c90eca7e251"}, + {file = "identify-2.6.9-py2.py3-none-any.whl", hash = "sha256:c98b4322da415a8e5a70ff6e51fbc2d2932c015532d77e9f8537b4ba7813b150"}, + {file = "identify-2.6.9.tar.gz", hash = "sha256:d40dfe3142a1421d8518e3d3985ef5ac42890683e32306ad614a29490abeb6bf"}, ] [package.extras] @@ -1269,14 +1272,14 @@ files = [ [[package]] name = "jinja2" -version = "3.1.5" +version = "3.1.6" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, - {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, ] [package.dependencies] @@ -1306,6 +1309,8 @@ python-versions = "*" groups = ["main"] files = [ {file = "jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c"}, + {file = "jsonpath_ng-1.7.0-py2-none-any.whl", hash = "sha256:898c93fc173f0c336784a3fa63d7434297544b7198124a68f9a3ef9597b0ae6e"}, + {file = "jsonpath_ng-1.7.0-py3-none-any.whl", hash = "sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6"}, ] [package.dependencies] @@ -1329,158 +1334,158 @@ typing-extensions = ">=4.5.0" [[package]] name = "lxml" -version = "5.3.0" +version = "5.3.1" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=3.6" groups = ["main"] files = [ - {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"}, - {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32"}, - {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86"}, - {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5"}, - {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03"}, - {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7"}, - {file = "lxml-5.3.0-cp310-cp310-win32.whl", hash = "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80"}, - {file = "lxml-5.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3"}, - {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b"}, - {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654"}, - {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d"}, - {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763"}, - {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec"}, - {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be"}, - {file = "lxml-5.3.0-cp311-cp311-win32.whl", hash = "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9"}, - {file = "lxml-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1"}, - {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859"}, - {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99"}, - {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff"}, - {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a"}, - {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8"}, - {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d"}, - {file = "lxml-5.3.0-cp312-cp312-win32.whl", hash = "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30"}, - {file = "lxml-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f"}, - {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a"}, - {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832"}, - {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff"}, - {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd"}, - {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb"}, - {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b"}, - {file = "lxml-5.3.0-cp313-cp313-win32.whl", hash = "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957"}, - {file = "lxml-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d"}, - {file = "lxml-5.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8f0de2d390af441fe8b2c12626d103540b5d850d585b18fcada58d972b74a74e"}, - {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1afe0a8c353746e610bd9031a630a95bcfb1a720684c3f2b36c4710a0a96528f"}, - {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56b9861a71575f5795bde89256e7467ece3d339c9b43141dbdd54544566b3b94"}, - {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:9fb81d2824dff4f2e297a276297e9031f46d2682cafc484f49de182aa5e5df99"}, - {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2c226a06ecb8cdef28845ae976da407917542c5e6e75dcac7cc33eb04aaeb237"}, - {file = "lxml-5.3.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:7d3d1ca42870cdb6d0d29939630dbe48fa511c203724820fc0fd507b2fb46577"}, - {file = "lxml-5.3.0-cp36-cp36m-win32.whl", hash = "sha256:094cb601ba9f55296774c2d57ad68730daa0b13dc260e1f941b4d13678239e70"}, - {file = "lxml-5.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:eafa2c8658f4e560b098fe9fc54539f86528651f61849b22111a9b107d18910c"}, - {file = "lxml-5.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb83f8a875b3d9b458cada4f880fa498646874ba4011dc974e071a0a84a1b033"}, - {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25f1b69d41656b05885aa185f5fdf822cb01a586d1b32739633679699f220391"}, - {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23e0553b8055600b3bf4a00b255ec5c92e1e4aebf8c2c09334f8368e8bd174d6"}, - {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ada35dd21dc6c039259596b358caab6b13f4db4d4a7f8665764d616daf9cc1d"}, - {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:81b4e48da4c69313192d8c8d4311e5d818b8be1afe68ee20f6385d0e96fc9512"}, - {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:2bc9fd5ca4729af796f9f59cd8ff160fe06a474da40aca03fcc79655ddee1a8b"}, - {file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:07da23d7ee08577760f0a71d67a861019103e4812c87e2fab26b039054594cc5"}, - {file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:ea2e2f6f801696ad7de8aec061044d6c8c0dd4037608c7cab38a9a4d316bfb11"}, - {file = "lxml-5.3.0-cp37-cp37m-win32.whl", hash = "sha256:5c54afdcbb0182d06836cc3d1be921e540be3ebdf8b8a51ee3ef987537455f84"}, - {file = "lxml-5.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f2901429da1e645ce548bf9171784c0f74f0718c3f6150ce166be39e4dd66c3e"}, - {file = "lxml-5.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c56a1d43b2f9ee4786e4658c7903f05da35b923fb53c11025712562d5cc02753"}, - {file = "lxml-5.3.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ee8c39582d2652dcd516d1b879451500f8db3fe3607ce45d7c5957ab2596040"}, - {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdf3a3059611f7585a78ee10399a15566356116a4288380921a4b598d807a22"}, - {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:146173654d79eb1fc97498b4280c1d3e1e5d58c398fa530905c9ea50ea849b22"}, - {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:0a7056921edbdd7560746f4221dca89bb7a3fe457d3d74267995253f46343f15"}, - {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:9e4b47ac0f5e749cfc618efdf4726269441014ae1d5583e047b452a32e221920"}, - {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945"}, - {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:213261f168c5e1d9b7535a67e68b1f59f92398dd17a56d934550837143f79c42"}, - {file = "lxml-5.3.0-cp38-cp38-win32.whl", hash = "sha256:218c1b2e17a710e363855594230f44060e2025b05c80d1f0661258142b2add2e"}, - {file = "lxml-5.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:315f9542011b2c4e1d280e4a20ddcca1761993dda3afc7a73b01235f8641e903"}, - {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1ffc23010330c2ab67fac02781df60998ca8fe759e8efde6f8b756a20599c5de"}, - {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2b3778cb38212f52fac9fe913017deea2fdf4eb1a4f8e4cfc6b009a13a6d3fcc"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b0c7a688944891086ba192e21c5229dea54382f4836a209ff8d0a660fac06be"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:747a3d3e98e24597981ca0be0fd922aebd471fa99d0043a3842d00cdcad7ad6a"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86a6b24b19eaebc448dc56b87c4865527855145d851f9fc3891673ff97950540"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b11a5d918a6216e521c715b02749240fb07ae5a1fefd4b7bf12f833bc8b4fe70"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68b87753c784d6acb8a25b05cb526c3406913c9d988d51f80adecc2b0775d6aa"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:109fa6fede314cc50eed29e6e56c540075e63d922455346f11e4d7a036d2b8cf"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:02ced472497b8362c8e902ade23e3300479f4f43e45f4105c85ef43b8db85229"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:6b038cc86b285e4f9fea2ba5ee76e89f21ed1ea898e287dc277a25884f3a7dfe"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:7437237c6a66b7ca341e868cda48be24b8701862757426852c9b3186de1da8a2"}, - {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7f41026c1d64043a36fda21d64c5026762d53a77043e73e94b71f0521939cc71"}, - {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:482c2f67761868f0108b1743098640fbb2a28a8e15bf3f47ada9fa59d9fe08c3"}, - {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1483fd3358963cc5c1c9b122c80606a3a79ee0875bcac0204149fa09d6ff2727"}, - {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dec2d1130a9cda5b904696cec33b2cfb451304ba9081eeda7f90f724097300a"}, - {file = "lxml-5.3.0-cp39-cp39-win32.whl", hash = "sha256:a0eabd0a81625049c5df745209dc7fcef6e2aea7793e5f003ba363610aa0a3ff"}, - {file = "lxml-5.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:89e043f1d9d341c52bf2af6d02e6adde62e0a46e6755d5eb60dc6e4f0b8aeca2"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:94d6c3782907b5e40e21cadf94b13b0842ac421192f26b84c45f13f3c9d5dc27"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c300306673aa0f3ed5ed9372b21867690a17dba38c68c44b287437c362ce486b"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d9b952e07aed35fe2e1a7ad26e929595412db48535921c5013edc8aa4a35ce"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2d9b8d9177afaef80c53c0a9e30fa252ff3036fb1c6494d427c066a4ce6a282f"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:20094fc3f21ea0a8669dc4c61ed7fa8263bd37d97d93b90f28fc613371e7a875"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ace2c2326a319a0bb8a8b0e5b570c764962e95818de9f259ce814ee666603f19"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92e67a0be1639c251d21e35fe74df6bcc40cba445c2cda7c4a967656733249e2"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd5350b55f9fecddc51385463a4f67a5da829bc741e38cf689f38ec9023f54ab"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c1fefd7e3d00921c44dc9ca80a775af49698bbfd92ea84498e56acffd4c5469"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:71a8dd38fbd2f2319136d4ae855a7078c69c9a38ae06e0c17c73fd70fc6caad8"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:97acf1e1fd66ab53dacd2c35b319d7e548380c2e9e8c54525c6e76d21b1ae3b1"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:68934b242c51eb02907c5b81d138cb977b2129a0a75a8f8b60b01cb8586c7b21"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b710bc2b8292966b23a6a0121f7a6c51d45d2347edcc75f016ac123b8054d3f2"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18feb4b93302091b1541221196a2155aa296c363fd233814fa11e181adebc52f"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3eb44520c4724c2e1a57c0af33a379eee41792595023f367ba3952a2d96c2aab"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:609251a0ca4770e5a8768ff902aa02bf636339c5a93f9349b48eb1f606f7f3e9"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:516f491c834eb320d6c843156440fe7fc0d50b33e44387fcec5b02f0bc118a4c"}, - {file = "lxml-5.3.0.tar.gz", hash = "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f"}, + {file = "lxml-5.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a4058f16cee694577f7e4dd410263cd0ef75644b43802a689c2b3c2a7e69453b"}, + {file = "lxml-5.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:364de8f57d6eda0c16dcfb999af902da31396949efa0e583e12675d09709881b"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:528f3a0498a8edc69af0559bdcf8a9f5a8bf7c00051a6ef3141fdcf27017bbf5"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db4743e30d6f5f92b6d2b7c86b3ad250e0bad8dee4b7ad8a0c44bfb276af89a3"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17b5d7f8acf809465086d498d62a981fa6a56d2718135bb0e4aa48c502055f5c"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:928e75a7200a4c09e6efc7482a1337919cc61fe1ba289f297827a5b76d8969c2"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a997b784a639e05b9d4053ef3b20c7e447ea80814a762f25b8ed5a89d261eac"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:7b82e67c5feb682dbb559c3e6b78355f234943053af61606af126df2183b9ef9"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:f1de541a9893cf8a1b1db9bf0bf670a2decab42e3e82233d36a74eda7822b4c9"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:de1fc314c3ad6bc2f6bd5b5a5b9357b8c6896333d27fdbb7049aea8bd5af2d79"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:7c0536bd9178f754b277a3e53f90f9c9454a3bd108b1531ffff720e082d824f2"}, + {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:68018c4c67d7e89951a91fbd371e2e34cd8cfc71f0bb43b5332db38497025d51"}, + {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aa826340a609d0c954ba52fd831f0fba2a4165659ab0ee1a15e4aac21f302406"}, + {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:796520afa499732191e39fc95b56a3b07f95256f2d22b1c26e217fb69a9db5b5"}, + {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3effe081b3135237da6e4c4530ff2a868d3f80be0bda027e118a5971285d42d0"}, + {file = "lxml-5.3.1-cp310-cp310-win32.whl", hash = "sha256:a22f66270bd6d0804b02cd49dae2b33d4341015545d17f8426f2c4e22f557a23"}, + {file = "lxml-5.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:0bcfadea3cdc68e678d2b20cb16a16716887dd00a881e16f7d806c2138b8ff0c"}, + {file = "lxml-5.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e220f7b3e8656ab063d2eb0cd536fafef396829cafe04cb314e734f87649058f"}, + {file = "lxml-5.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f2cfae0688fd01f7056a17367e3b84f37c545fb447d7282cf2c242b16262607"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67d2f8ad9dcc3a9e826bdc7802ed541a44e124c29b7d95a679eeb58c1c14ade8"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db0c742aad702fd5d0c6611a73f9602f20aec2007c102630c06d7633d9c8f09a"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:198bb4b4dd888e8390afa4f170d4fa28467a7eaf857f1952589f16cfbb67af27"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2a3e412ce1849be34b45922bfef03df32d1410a06d1cdeb793a343c2f1fd666"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b8969dbc8d09d9cd2ae06362c3bad27d03f433252601ef658a49bd9f2b22d79"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5be8f5e4044146a69c96077c7e08f0709c13a314aa5315981185c1f00235fe65"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:133f3493253a00db2c870d3740bc458ebb7d937bd0a6a4f9328373e0db305709"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:52d82b0d436edd6a1d22d94a344b9a58abd6c68c357ed44f22d4ba8179b37629"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b6f92e35e2658a5ed51c6634ceb5ddae32053182851d8cad2a5bc102a359b33"}, + {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:203b1d3eaebd34277be06a3eb880050f18a4e4d60861efba4fb946e31071a295"}, + {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:155e1a5693cf4b55af652f5c0f78ef36596c7f680ff3ec6eb4d7d85367259b2c"}, + {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22ec2b3c191f43ed21f9545e9df94c37c6b49a5af0a874008ddc9132d49a2d9c"}, + {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7eda194dd46e40ec745bf76795a7cccb02a6a41f445ad49d3cf66518b0bd9cff"}, + {file = "lxml-5.3.1-cp311-cp311-win32.whl", hash = "sha256:fb7c61d4be18e930f75948705e9718618862e6fc2ed0d7159b2262be73f167a2"}, + {file = "lxml-5.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:c809eef167bf4a57af4b03007004896f5c60bd38dc3852fcd97a26eae3d4c9e6"}, + {file = "lxml-5.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e69add9b6b7b08c60d7ff0152c7c9a6c45b4a71a919be5abde6f98f1ea16421c"}, + {file = "lxml-5.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4e52e1b148867b01c05e21837586ee307a01e793b94072d7c7b91d2c2da02ffe"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4b382e0e636ed54cd278791d93fe2c4f370772743f02bcbe431a160089025c9"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2e49dc23a10a1296b04ca9db200c44d3eb32c8d8ec532e8c1fd24792276522a"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4399b4226c4785575fb20998dc571bc48125dc92c367ce2602d0d70e0c455eb0"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5412500e0dc5481b1ee9cf6b38bb3b473f6e411eb62b83dc9b62699c3b7b79f7"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c93ed3c998ea8472be98fb55aed65b5198740bfceaec07b2eba551e55b7b9ae"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:63d57fc94eb0bbb4735e45517afc21ef262991d8758a8f2f05dd6e4174944519"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:b450d7cabcd49aa7ab46a3c6aa3ac7e1593600a1a0605ba536ec0f1b99a04322"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:4df0ec814b50275ad6a99bc82a38b59f90e10e47714ac9871e1b223895825468"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d184f85ad2bb1f261eac55cddfcf62a70dee89982c978e92b9a74a1bfef2e367"}, + {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b725e70d15906d24615201e650d5b0388b08a5187a55f119f25874d0103f90dd"}, + {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a31fa7536ec1fb7155a0cd3a4e3d956c835ad0a43e3610ca32384d01f079ea1c"}, + {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3c3c8b55c7fc7b7e8877b9366568cc73d68b82da7fe33d8b98527b73857a225f"}, + {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d61ec60945d694df806a9aec88e8f29a27293c6e424f8ff91c80416e3c617645"}, + {file = "lxml-5.3.1-cp312-cp312-win32.whl", hash = "sha256:f4eac0584cdc3285ef2e74eee1513a6001681fd9753b259e8159421ed28a72e5"}, + {file = "lxml-5.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:29bfc8d3d88e56ea0a27e7c4897b642706840247f59f4377d81be8f32aa0cfbf"}, + {file = "lxml-5.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c093c7088b40d8266f57ed71d93112bd64c6724d31f0794c1e52cc4857c28e0e"}, + {file = "lxml-5.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0884e3f22d87c30694e625b1e62e6f30d39782c806287450d9dc2fdf07692fd"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1637fa31ec682cd5760092adfabe86d9b718a75d43e65e211d5931809bc111e7"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a364e8e944d92dcbf33b6b494d4e0fb3499dcc3bd9485beb701aa4b4201fa414"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:779e851fd0e19795ccc8a9bb4d705d6baa0ef475329fe44a13cf1e962f18ff1e"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c4393600915c308e546dc7003d74371744234e8444a28622d76fe19b98fa59d1"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:673b9d8e780f455091200bba8534d5f4f465944cbdd61f31dc832d70e29064a5"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:2e4a570f6a99e96c457f7bec5ad459c9c420ee80b99eb04cbfcfe3fc18ec6423"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:71f31eda4e370f46af42fc9f264fafa1b09f46ba07bdbee98f25689a04b81c20"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:42978a68d3825eaac55399eb37a4d52012a205c0c6262199b8b44fcc6fd686e8"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:8b1942b3e4ed9ed551ed3083a2e6e0772de1e5e3aca872d955e2e86385fb7ff9"}, + {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:85c4f11be9cf08917ac2a5a8b6e1ef63b2f8e3799cec194417e76826e5f1de9c"}, + {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:231cf4d140b22a923b1d0a0a4e0b4f972e5893efcdec188934cc65888fd0227b"}, + {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5865b270b420eda7b68928d70bb517ccbe045e53b1a428129bb44372bf3d7dd5"}, + {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dbf7bebc2275016cddf3c997bf8a0f7044160714c64a9b83975670a04e6d2252"}, + {file = "lxml-5.3.1-cp313-cp313-win32.whl", hash = "sha256:d0751528b97d2b19a388b302be2a0ee05817097bab46ff0ed76feeec24951f78"}, + {file = "lxml-5.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:91fb6a43d72b4f8863d21f347a9163eecbf36e76e2f51068d59cd004c506f332"}, + {file = "lxml-5.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:016b96c58e9a4528219bb563acf1aaaa8bc5452e7651004894a973f03b84ba81"}, + {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82a4bb10b0beef1434fb23a09f001ab5ca87895596b4581fd53f1e5145a8934a"}, + {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d68eeef7b4d08a25e51897dac29bcb62aba830e9ac6c4e3297ee7c6a0cf6439"}, + {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:f12582b8d3b4c6be1d298c49cb7ae64a3a73efaf4c2ab4e37db182e3545815ac"}, + {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2df7ed5edeb6bd5590914cd61df76eb6cce9d590ed04ec7c183cf5509f73530d"}, + {file = "lxml-5.3.1-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:585c4dc429deebc4307187d2b71ebe914843185ae16a4d582ee030e6cfbb4d8a"}, + {file = "lxml-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:06a20d607a86fccab2fc15a77aa445f2bdef7b49ec0520a842c5c5afd8381576"}, + {file = "lxml-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:057e30d0012439bc54ca427a83d458752ccda725c1c161cc283db07bcad43cf9"}, + {file = "lxml-5.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4867361c049761a56bd21de507cab2c2a608c55102311d142ade7dab67b34f32"}, + {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dddf0fb832486cc1ea71d189cb92eb887826e8deebe128884e15020bb6e3f61"}, + {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bcc211542f7af6f2dfb705f5f8b74e865592778e6cafdfd19c792c244ccce19"}, + {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaca5a812f050ab55426c32177091130b1e49329b3f002a32934cd0245571307"}, + {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:236610b77589faf462337b3305a1be91756c8abc5a45ff7ca8f245a71c5dab70"}, + {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:aed57b541b589fa05ac248f4cb1c46cbb432ab82cbd467d1c4f6a2bdc18aecf9"}, + {file = "lxml-5.3.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:75fa3d6946d317ffc7016a6fcc44f42db6d514b7fdb8b4b28cbe058303cb6e53"}, + {file = "lxml-5.3.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:96eef5b9f336f623ffc555ab47a775495e7e8846dde88de5f941e2906453a1ce"}, + {file = "lxml-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:ef45f31aec9be01379fc6c10f1d9c677f032f2bac9383c827d44f620e8a88407"}, + {file = "lxml-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0611da6b07dd3720f492db1b463a4d1175b096b49438761cc9f35f0d9eaaef5"}, + {file = "lxml-5.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b2aca14c235c7a08558fe0a4786a1a05873a01e86b474dfa8f6df49101853a4e"}, + {file = "lxml-5.3.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae82fce1d964f065c32c9517309f0c7be588772352d2f40b1574a214bd6e6098"}, + {file = "lxml-5.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7aae7a3d63b935babfdc6864b31196afd5145878ddd22f5200729006366bc4d5"}, + {file = "lxml-5.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8e0d177b1fe251c3b1b914ab64135475c5273c8cfd2857964b2e3bb0fe196a7"}, + {file = "lxml-5.3.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:6c4dd3bfd0c82400060896717dd261137398edb7e524527438c54a8c34f736bf"}, + {file = "lxml-5.3.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f1208c1c67ec9e151d78aa3435aa9b08a488b53d9cfac9b699f15255a3461ef2"}, + {file = "lxml-5.3.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:c6aacf00d05b38a5069826e50ae72751cb5bc27bdc4d5746203988e429b385bb"}, + {file = "lxml-5.3.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5881aaa4bf3a2d086c5f20371d3a5856199a0d8ac72dd8d0dbd7a2ecfc26ab73"}, + {file = "lxml-5.3.1-cp38-cp38-win32.whl", hash = "sha256:45fbb70ccbc8683f2fb58bea89498a7274af1d9ec7995e9f4af5604e028233fc"}, + {file = "lxml-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:7512b4d0fc5339d5abbb14d1843f70499cab90d0b864f790e73f780f041615d7"}, + {file = "lxml-5.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5885bc586f1edb48e5d68e7a4b4757b5feb2a496b64f462b4d65950f5af3364f"}, + {file = "lxml-5.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1b92fe86e04f680b848fff594a908edfa72b31bfc3499ef7433790c11d4c8cd8"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a091026c3bf7519ab1e64655a3f52a59ad4a4e019a6f830c24d6430695b1cf6a"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ffb141361108e864ab5f1813f66e4e1164181227f9b1f105b042729b6c15125"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3715cdf0dd31b836433af9ee9197af10e3df41d273c19bb249230043667a5dfd"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88b72eb7222d918c967202024812c2bfb4048deeb69ca328363fb8e15254c549"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa59974880ab5ad8ef3afaa26f9bda148c5f39e06b11a8ada4660ecc9fb2feb3"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3bb8149840daf2c3f97cebf00e4ed4a65a0baff888bf2605a8d0135ff5cf764e"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:0d6b2fa86becfa81f0a0271ccb9eb127ad45fb597733a77b92e8a35e53414914"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:136bf638d92848a939fd8f0e06fcf92d9f2e4b57969d94faae27c55f3d85c05b"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:89934f9f791566e54c1d92cdc8f8fd0009447a5ecdb1ec6b810d5f8c4955f6be"}, + {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a8ade0363f776f87f982572c2860cc43c65ace208db49c76df0a21dde4ddd16e"}, + {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:bfbbab9316330cf81656fed435311386610f78b6c93cc5db4bebbce8dd146675"}, + {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:172d65f7c72a35a6879217bcdb4bb11bc88d55fb4879e7569f55616062d387c2"}, + {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e3c623923967f3e5961d272718655946e5322b8d058e094764180cdee7bab1af"}, + {file = "lxml-5.3.1-cp39-cp39-win32.whl", hash = "sha256:ce0930a963ff593e8bb6fda49a503911accc67dee7e5445eec972668e672a0f0"}, + {file = "lxml-5.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:f7b64fcd670bca8800bc10ced36620c6bbb321e7bc1214b9c0c0df269c1dddc2"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:afa578b6524ff85fb365f454cf61683771d0170470c48ad9d170c48075f86725"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f5e80adf0aafc7b5454f2c1cb0cde920c9b1f2cbd0485f07cc1d0497c35c5d"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dd0b80ac2d8f13ffc906123a6f20b459cb50a99222d0da492360512f3e50f84"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:422c179022ecdedbe58b0e242607198580804253da220e9454ffe848daa1cfd2"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:524ccfded8989a6595dbdda80d779fb977dbc9a7bc458864fc9a0c2fc15dc877"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:48fd46bf7155def2e15287c6f2b133a2f78e2d22cdf55647269977b873c65499"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:05123fad495a429f123307ac6d8fd6f977b71e9a0b6d9aeeb8f80c017cb17131"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a243132767150a44e6a93cd1dde41010036e1cbc63cc3e9fe1712b277d926ce3"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c92ea6d9dd84a750b2bae72ff5e8cf5fdd13e58dda79c33e057862c29a8d5b50"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2f1be45d4c15f237209bbf123a0e05b5d630c8717c42f59f31ea9eae2ad89394"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:a83d3adea1e0ee36dac34627f78ddd7f093bb9cfc0a8e97f1572a949b695cb98"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:3edbb9c9130bac05d8c3fe150c51c337a471cc7fdb6d2a0a7d3a88e88a829314"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2f23cf50eccb3255b6e913188291af0150d89dab44137a69e14e4dcb7be981f1"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df7e5edac4778127f2bf452e0721a58a1cfa4d1d9eac63bdd650535eb8543615"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:094b28ed8a8a072b9e9e2113a81fda668d2053f2ca9f2d202c2c8c7c2d6516b1"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:514fe78fc4b87e7a7601c92492210b20a1b0c6ab20e71e81307d9c2e377c64de"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8fffc08de02071c37865a155e5ea5fce0282e1546fd5bde7f6149fcaa32558ac"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4b0d5cdba1b655d5b18042ac9c9ff50bda33568eb80feaaca4fc237b9c4fbfde"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3031e4c16b59424e8d78522c69b062d301d951dc55ad8685736c3335a97fc270"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb659702a45136c743bc130760c6f137870d4df3a9e14386478b8a0511abcfca"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a11b16a33656ffc43c92a5343a28dc71eefe460bcc2a4923a96f292692709f6"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c5ae125276f254b01daa73e2c103363d3e99e3e10505686ac7d9d2442dd4627a"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c76722b5ed4a31ba103e0dc77ab869222ec36efe1a614e42e9bcea88a36186fe"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:33e06717c00c788ab4e79bc4726ecc50c54b9bfb55355eae21473c145d83c2d2"}, + {file = "lxml-5.3.1.tar.gz", hash = "sha256:106b7b5d2977b339f1e97efe2778e2ab20e99994cbb0ec5e55771ed0795920c8"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] -html-clean = ["lxml-html-clean"] +html-clean = ["lxml_html_clean"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=3.0.11)"] +source = ["Cython (>=3.0.11,<3.1.0)"] [[package]] name = "markdown" @@ -1957,94 +1962,110 @@ wcwidth = "*" [[package]] name = "propcache" -version = "0.2.1" +version = "0.3.0" description = "Accelerated property cache" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6"}, - {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2"}, - {file = "propcache-0.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea"}, - {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212"}, - {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3"}, - {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d"}, - {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634"}, - {file = "propcache-0.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034"}, - {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b"}, - {file = "propcache-0.2.1-cp310-cp310-win32.whl", hash = "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4"}, - {file = "propcache-0.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba"}, - {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16"}, - {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717"}, - {file = "propcache-0.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3"}, - {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9"}, - {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787"}, - {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465"}, - {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af"}, - {file = "propcache-0.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca"}, - {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e"}, - {file = "propcache-0.2.1-cp311-cp311-win32.whl", hash = "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034"}, - {file = "propcache-0.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3"}, - {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a"}, - {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0"}, - {file = "propcache-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d"}, - {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4"}, - {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d"}, - {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5"}, - {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24"}, - {file = "propcache-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6"}, - {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518"}, - {file = "propcache-0.2.1-cp312-cp312-win32.whl", hash = "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246"}, - {file = "propcache-0.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1"}, - {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc"}, - {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9"}, - {file = "propcache-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439"}, - {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536"}, - {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629"}, - {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b"}, - {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052"}, - {file = "propcache-0.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f"}, - {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30"}, - {file = "propcache-0.2.1-cp313-cp313-win32.whl", hash = "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6"}, - {file = "propcache-0.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1"}, - {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6a9a8c34fb7bb609419a211e59da8887eeca40d300b5ea8e56af98f6fbbb1541"}, - {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ae1aa1cd222c6d205853b3013c69cd04515f9d6ab6de4b0603e2e1c33221303e"}, - {file = "propcache-0.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:accb6150ce61c9c4b7738d45550806aa2b71c7668c6942f17b0ac182b6142fd4"}, - {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5eee736daafa7af6d0a2dc15cc75e05c64f37fc37bafef2e00d77c14171c2097"}, - {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7a31fc1e1bd362874863fdeed71aed92d348f5336fd84f2197ba40c59f061bd"}, - {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba4cfa1052819d16699e1d55d18c92b6e094d4517c41dd231a8b9f87b6fa681"}, - {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f089118d584e859c62b3da0892b88a83d611c2033ac410e929cb6754eec0ed16"}, - {file = "propcache-0.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:781e65134efaf88feb447e8c97a51772aa75e48b794352f94cb7ea717dedda0d"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31f5af773530fd3c658b32b6bdc2d0838543de70eb9a2156c03e410f7b0d3aae"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:a7a078f5d37bee6690959c813977da5291b24286e7b962e62a94cec31aa5188b"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cea7daf9fc7ae6687cf1e2c049752f19f146fdc37c2cc376e7d0032cf4f25347"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:8b3489ff1ed1e8315674d0775dc7d2195fb13ca17b3808721b54dbe9fd020faf"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9403db39be1393618dd80c746cb22ccda168efce239c73af13c3763ef56ffc04"}, - {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5d97151bc92d2b2578ff7ce779cdb9174337390a535953cbb9452fb65164c587"}, - {file = "propcache-0.2.1-cp39-cp39-win32.whl", hash = "sha256:9caac6b54914bdf41bcc91e7eb9147d331d29235a7c967c150ef5df6464fd1bb"}, - {file = "propcache-0.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:92fc4500fcb33899b05ba73276dfb684a20d31caa567b7cb5252d48f896a91b1"}, - {file = "propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54"}, - {file = "propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64"}, + {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:efa44f64c37cc30c9f05932c740a8b40ce359f51882c70883cc95feac842da4d"}, + {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2383a17385d9800b6eb5855c2f05ee550f803878f344f58b6e194de08b96352c"}, + {file = "propcache-0.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3e7420211f5a65a54675fd860ea04173cde60a7cc20ccfbafcccd155225f8bc"}, + {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3302c5287e504d23bb0e64d2a921d1eb4a03fb93a0a0aa3b53de059f5a5d737d"}, + {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e2e068a83552ddf7a39a99488bcba05ac13454fb205c847674da0352602082f"}, + {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d913d36bdaf368637b4f88d554fb9cb9d53d6920b9c5563846555938d5450bf"}, + {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ee1983728964d6070ab443399c476de93d5d741f71e8f6e7880a065f878e0b9"}, + {file = "propcache-0.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:36ca5e9a21822cc1746023e88f5c0af6fce3af3b85d4520efb1ce4221bed75cc"}, + {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9ecde3671e62eeb99e977f5221abcf40c208f69b5eb986b061ccec317c82ebd0"}, + {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d383bf5e045d7f9d239b38e6acadd7b7fdf6c0087259a84ae3475d18e9a2ae8b"}, + {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8cb625bcb5add899cb8ba7bf716ec1d3e8f7cdea9b0713fa99eadf73b6d4986f"}, + {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5fa159dcee5dba00c1def3231c249cf261185189205073bde13797e57dd7540a"}, + {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a7080b0159ce05f179cfac592cda1a82898ca9cd097dacf8ea20ae33474fbb25"}, + {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ed7161bccab7696a473fe7ddb619c1d75963732b37da4618ba12e60899fefe4f"}, + {file = "propcache-0.3.0-cp310-cp310-win32.whl", hash = "sha256:bf0d9a171908f32d54f651648c7290397b8792f4303821c42a74e7805bfb813c"}, + {file = "propcache-0.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:42924dc0c9d73e49908e35bbdec87adedd651ea24c53c29cac103ede0ea1d340"}, + {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9ddd49258610499aab83b4f5b61b32e11fce873586282a0e972e5ab3bcadee51"}, + {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2578541776769b500bada3f8a4eeaf944530516b6e90c089aa368266ed70c49e"}, + {file = "propcache-0.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8074c5dd61c8a3e915fa8fc04754fa55cfa5978200d2daa1e2d4294c1f136aa"}, + {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b58229a844931bca61b3a20efd2be2a2acb4ad1622fc026504309a6883686fbf"}, + {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e45377d5d6fefe1677da2a2c07b024a6dac782088e37c0b1efea4cfe2b1be19b"}, + {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec5060592d83454e8063e487696ac3783cc48c9a329498bafae0d972bc7816c9"}, + {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15010f29fbed80e711db272909a074dc79858c6d28e2915704cfc487a8ac89c6"}, + {file = "propcache-0.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a254537b9b696ede293bfdbc0a65200e8e4507bc9f37831e2a0318a9b333c85c"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2b975528998de037dfbc10144b8aed9b8dd5a99ec547f14d1cb7c5665a43f075"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:19d36bb351ad5554ff20f2ae75f88ce205b0748c38b146c75628577020351e3c"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6032231d4a5abd67c7f71168fd64a47b6b451fbcb91c8397c2f7610e67683810"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6985a593417cdbc94c7f9c3403747335e450c1599da1647a5af76539672464d3"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6a1948df1bb1d56b5e7b0553c0fa04fd0e320997ae99689488201f19fa90d2e7"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8319293e85feadbbfe2150a5659dbc2ebc4afdeaf7d98936fb9a2f2ba0d4c35c"}, + {file = "propcache-0.3.0-cp311-cp311-win32.whl", hash = "sha256:63f26258a163c34542c24808f03d734b338da66ba91f410a703e505c8485791d"}, + {file = "propcache-0.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:cacea77ef7a2195f04f9279297684955e3d1ae4241092ff0cfcef532bb7a1c32"}, + {file = "propcache-0.3.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e53d19c2bf7d0d1e6998a7e693c7e87300dd971808e6618964621ccd0e01fe4e"}, + {file = "propcache-0.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a61a68d630e812b67b5bf097ab84e2cd79b48c792857dc10ba8a223f5b06a2af"}, + {file = "propcache-0.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fb91d20fa2d3b13deea98a690534697742029f4fb83673a3501ae6e3746508b5"}, + {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67054e47c01b7b349b94ed0840ccae075449503cf1fdd0a1fdd98ab5ddc2667b"}, + {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997e7b8f173a391987df40f3b52c423e5850be6f6df0dcfb5376365440b56667"}, + {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d663fd71491dde7dfdfc899d13a067a94198e90695b4321084c6e450743b8c7"}, + {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8884ba1a0fe7210b775106b25850f5e5a9dc3c840d1ae9924ee6ea2eb3acbfe7"}, + {file = "propcache-0.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa806bbc13eac1ab6291ed21ecd2dd426063ca5417dd507e6be58de20e58dfcf"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6f4d7a7c0aff92e8354cceca6fe223973ddf08401047920df0fcb24be2bd5138"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9be90eebc9842a93ef8335291f57b3b7488ac24f70df96a6034a13cb58e6ff86"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bf15fc0b45914d9d1b706f7c9c4f66f2b7b053e9517e40123e137e8ca8958b3d"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5a16167118677d94bb48bfcd91e420088854eb0737b76ec374b91498fb77a70e"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:41de3da5458edd5678b0f6ff66691507f9885f5fe6a0fb99a5d10d10c0fd2d64"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:728af36011bb5d344c4fe4af79cfe186729efb649d2f8b395d1572fb088a996c"}, + {file = "propcache-0.3.0-cp312-cp312-win32.whl", hash = "sha256:6b5b7fd6ee7b54e01759f2044f936dcf7dea6e7585f35490f7ca0420fe723c0d"}, + {file = "propcache-0.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:2d15bc27163cd4df433e75f546b9ac31c1ba7b0b128bfb1b90df19082466ff57"}, + {file = "propcache-0.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a2b9bf8c79b660d0ca1ad95e587818c30ccdb11f787657458d6f26a1ea18c568"}, + {file = "propcache-0.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0c1a133d42c6fc1f5fbcf5c91331657a1ff822e87989bf4a6e2e39b818d0ee9"}, + {file = "propcache-0.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bb2f144c6d98bb5cbc94adeb0447cfd4c0f991341baa68eee3f3b0c9c0e83767"}, + {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1323cd04d6e92150bcc79d0174ce347ed4b349d748b9358fd2e497b121e03c8"}, + {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b812b3cb6caacd072276ac0492d249f210006c57726b6484a1e1805b3cfeea0"}, + {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:742840d1d0438eb7ea4280f3347598f507a199a35a08294afdcc560c3739989d"}, + {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c6e7e4f9167fddc438cd653d826f2222222564daed4116a02a184b464d3ef05"}, + {file = "propcache-0.3.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a94ffc66738da99232ddffcf7910e0f69e2bbe3a0802e54426dbf0714e1c2ffe"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c6ec957025bf32b15cbc6b67afe233c65b30005e4c55fe5768e4bb518d712f1"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:549722908de62aa0b47a78b90531c022fa6e139f9166be634f667ff45632cc92"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5d62c4f6706bff5d8a52fd51fec6069bef69e7202ed481486c0bc3874912c787"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:24c04f8fbf60094c531667b8207acbae54146661657a1b1be6d3ca7773b7a545"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7c5f5290799a3f6539cc5e6f474c3e5c5fbeba74a5e1e5be75587746a940d51e"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4fa0e7c9c3cf7c276d4f6ab9af8adddc127d04e0fcabede315904d2ff76db626"}, + {file = "propcache-0.3.0-cp313-cp313-win32.whl", hash = "sha256:ee0bd3a7b2e184e88d25c9baa6a9dc609ba25b76daae942edfb14499ac7ec374"}, + {file = "propcache-0.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1c8f7d896a16da9455f882870a507567d4f58c53504dc2d4b1e1d386dfe4588a"}, + {file = "propcache-0.3.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e560fd75aaf3e5693b91bcaddd8b314f4d57e99aef8a6c6dc692f935cc1e6bbf"}, + {file = "propcache-0.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:65a37714b8ad9aba5780325228598a5b16c47ba0f8aeb3dc0514701e4413d7c0"}, + {file = "propcache-0.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:07700939b2cbd67bfb3b76a12e1412405d71019df00ca5697ce75e5ef789d829"}, + {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c0fdbdf6983526e269e5a8d53b7ae3622dd6998468821d660d0daf72779aefa"}, + {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:794c3dd744fad478b6232289c866c25406ecdfc47e294618bdf1697e69bd64a6"}, + {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4544699674faf66fb6b4473a1518ae4999c1b614f0b8297b1cef96bac25381db"}, + {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fddb8870bdb83456a489ab67c6b3040a8d5a55069aa6f72f9d872235fbc52f54"}, + {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f857034dc68d5ceb30fb60afb6ff2103087aea10a01b613985610e007053a121"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:02df07041e0820cacc8f739510078f2aadcfd3fc57eaeeb16d5ded85c872c89e"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f47d52fd9b2ac418c4890aad2f6d21a6b96183c98021f0a48497a904199f006e"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9ff4e9ecb6e4b363430edf2c6e50173a63e0820e549918adef70515f87ced19a"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ecc2920630283e0783c22e2ac94427f8cca29a04cfdf331467d4f661f4072dac"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:c441c841e82c5ba7a85ad25986014be8d7849c3cfbdb6004541873505929a74e"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c929916cbdb540d3407c66f19f73387f43e7c12fa318a66f64ac99da601bcdf"}, + {file = "propcache-0.3.0-cp313-cp313t-win32.whl", hash = "sha256:0c3e893c4464ebd751b44ae76c12c5f5c1e4f6cbd6fbf67e3783cd93ad221863"}, + {file = "propcache-0.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:75e872573220d1ee2305b35c9813626e620768248425f58798413e9c39741f46"}, + {file = "propcache-0.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:03c091bb752349402f23ee43bb2bff6bd80ccab7c9df6b88ad4322258d6960fc"}, + {file = "propcache-0.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:46ed02532cb66612d42ae5c3929b5e98ae330ea0f3900bc66ec5f4862069519b"}, + {file = "propcache-0.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11ae6a8a01b8a4dc79093b5d3ca2c8a4436f5ee251a9840d7790dccbd96cb649"}, + {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df03cd88f95b1b99052b52b1bb92173229d7a674df0ab06d2b25765ee8404bce"}, + {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03acd9ff19021bd0567582ac88f821b66883e158274183b9e5586f678984f8fe"}, + {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd54895e4ae7d32f1e3dd91261df46ee7483a735017dc6f987904f194aa5fd14"}, + {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26a67e5c04e3119594d8cfae517f4b9330c395df07ea65eab16f3d559b7068fe"}, + {file = "propcache-0.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee25f1ac091def37c4b59d192bbe3a206298feeb89132a470325bf76ad122a1e"}, + {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:58e6d2a5a7cb3e5f166fd58e71e9a4ff504be9dc61b88167e75f835da5764d07"}, + {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:be90c94570840939fecedf99fa72839aed70b0ced449b415c85e01ae67422c90"}, + {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:49ea05212a529c2caffe411e25a59308b07d6e10bf2505d77da72891f9a05641"}, + {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:119e244ab40f70a98c91906d4c1f4c5f2e68bd0b14e7ab0a06922038fae8a20f"}, + {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:507c5357a8d8b4593b97fb669c50598f4e6cccbbf77e22fa9598aba78292b4d7"}, + {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8526b0941ec5a40220fc4dfde76aed58808e2b309c03e9fa8e2260083ef7157f"}, + {file = "propcache-0.3.0-cp39-cp39-win32.whl", hash = "sha256:7cedd25e5f678f7738da38037435b340694ab34d424938041aa630d8bac42663"}, + {file = "propcache-0.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:bf4298f366ca7e1ad1d21bbb58300a6985015909964077afd37559084590c929"}, + {file = "propcache-0.3.0-py3-none-any.whl", hash = "sha256:67dda3c7325691c2081510e92c561f465ba61b975f481735aefdfc845d2cd043"}, + {file = "propcache-0.3.0.tar.gz", hash = "sha256:a8fd93de4e1d278046345f49e2238cdb298589325849b2645d4a94c53faeffc5"}, ] [[package]] @@ -2061,14 +2082,14 @@ files = [ [[package]] name = "pydantic" -version = "2.10.5" +version = "2.10.6" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"}, - {file = "pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff"}, + {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"}, + {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"}, ] [package.dependencies] @@ -2242,25 +2263,25 @@ files = [ [[package]] name = "pydevd-pycharm" -version = "251.18673.39" +version = "251.23774.37" description = "PyCharm Debugger (used in PyCharm and PyDev)" optional = false python-versions = "*" groups = ["dev"] files = [ - {file = "pydevd_pycharm-251.18673.39.tar.gz", hash = "sha256:52c3abb328050d6d367688d0999a8cce1d9bca59cddc0a237f955a14907bd68d"}, + {file = "pydevd_pycharm-251.23774.37.tar.gz", hash = "sha256:addbe1559edf1fcdf0aaf0bb66af6ae02bab0cd86447b296b477fe81a56b7909"}, ] [[package]] name = "pydid" -version = "0.5.1" +version = "0.5.2" description = "Python library for validating, constructing, and representing DIDs and DID Documents" optional = false python-versions = "<4.0.0,>=3.9.0" groups = ["main"] files = [ - {file = "pydid-0.5.1-py3-none-any.whl", hash = "sha256:be89df79b6267ec1814d49cdd240262c8bbddbfcee9e3aad97a97d521620d6c4"}, - {file = "pydid-0.5.1.tar.gz", hash = "sha256:9489a5fbfbecc8dc864c461bb5a0c664895726ab3ca83daf389d91a10146d5e2"}, + {file = "pydid-0.5.2-py3-none-any.whl", hash = "sha256:fcf4bea7b3313ba1581a69ce50fde96a7380f9ecfe0ac97f35db1b293c734925"}, + {file = "pydid-0.5.2.tar.gz", hash = "sha256:584db299a2e2570c4ece4f8f053a0fa230477298bb5b42d229ae567edf601c95"}, ] [package.dependencies] @@ -2338,14 +2359,14 @@ tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] [[package]] name = "pytest" -version = "8.3.4" +version = "8.3.5" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, - {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, + {file = "pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"}, + {file = "pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"}, ] [package.dependencies] @@ -2464,31 +2485,29 @@ dev = ["backports.zoneinfo ; python_version < \"3.9\"", "black", "build", "freez [[package]] name = "pywin32" -version = "308" +version = "309" description = "Python for Window Extensions" optional = false python-versions = "*" groups = ["main"] markers = "platform_system == \"Windows\"" files = [ - {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, - {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, - {file = "pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c"}, - {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"}, - {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"}, - {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"}, - {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, - {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, - {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, - {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"}, - {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"}, - {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"}, - {file = "pywin32-308-cp37-cp37m-win32.whl", hash = "sha256:1f696ab352a2ddd63bd07430080dd598e6369152ea13a25ebcdd2f503a38f1ff"}, - {file = "pywin32-308-cp37-cp37m-win_amd64.whl", hash = "sha256:13dcb914ed4347019fbec6697a01a0aec61019c1046c2b905410d197856326a6"}, - {file = "pywin32-308-cp38-cp38-win32.whl", hash = "sha256:5794e764ebcabf4ff08c555b31bd348c9025929371763b2183172ff4708152f0"}, - {file = "pywin32-308-cp38-cp38-win_amd64.whl", hash = "sha256:3b92622e29d651c6b783e368ba7d6722b1634b8e70bd376fd7610fe1992e19de"}, - {file = "pywin32-308-cp39-cp39-win32.whl", hash = "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341"}, - {file = "pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920"}, + {file = "pywin32-309-cp310-cp310-win32.whl", hash = "sha256:5b78d98550ca093a6fe7ab6d71733fbc886e2af9d4876d935e7f6e1cd6577ac9"}, + {file = "pywin32-309-cp310-cp310-win_amd64.whl", hash = "sha256:728d08046f3d65b90d4c77f71b6fbb551699e2005cc31bbffd1febd6a08aa698"}, + {file = "pywin32-309-cp310-cp310-win_arm64.whl", hash = "sha256:c667bcc0a1e6acaca8984eb3e2b6e42696fc035015f99ff8bc6c3db4c09a466a"}, + {file = "pywin32-309-cp311-cp311-win32.whl", hash = "sha256:d5df6faa32b868baf9ade7c9b25337fa5eced28eb1ab89082c8dae9c48e4cd51"}, + {file = "pywin32-309-cp311-cp311-win_amd64.whl", hash = "sha256:e7ec2cef6df0926f8a89fd64959eba591a1eeaf0258082065f7bdbe2121228db"}, + {file = "pywin32-309-cp311-cp311-win_arm64.whl", hash = "sha256:54ee296f6d11db1627216e9b4d4c3231856ed2d9f194c82f26c6cb5650163f4c"}, + {file = "pywin32-309-cp312-cp312-win32.whl", hash = "sha256:de9acacced5fa82f557298b1fed5fef7bd49beee04190f68e1e4783fbdc19926"}, + {file = "pywin32-309-cp312-cp312-win_amd64.whl", hash = "sha256:6ff9eebb77ffc3d59812c68db33c0a7817e1337e3537859499bd27586330fc9e"}, + {file = "pywin32-309-cp312-cp312-win_arm64.whl", hash = "sha256:619f3e0a327b5418d833f44dc87859523635cf339f86071cc65a13c07be3110f"}, + {file = "pywin32-309-cp313-cp313-win32.whl", hash = "sha256:008bffd4afd6de8ca46c6486085414cc898263a21a63c7f860d54c9d02b45c8d"}, + {file = "pywin32-309-cp313-cp313-win_amd64.whl", hash = "sha256:bd0724f58492db4cbfbeb1fcd606495205aa119370c0ddc4f70e5771a3ab768d"}, + {file = "pywin32-309-cp313-cp313-win_arm64.whl", hash = "sha256:8fd9669cfd41863b688a1bc9b1d4d2d76fd4ba2128be50a70b0ea66b8d37953b"}, + {file = "pywin32-309-cp38-cp38-win32.whl", hash = "sha256:617b837dc5d9dfa7e156dbfa7d3906c009a2881849a80a9ae7519f3dd8c6cb86"}, + {file = "pywin32-309-cp38-cp38-win_amd64.whl", hash = "sha256:0be3071f555480fbfd86a816a1a773880ee655bf186aa2931860dbb44e8424f8"}, + {file = "pywin32-309-cp39-cp39-win32.whl", hash = "sha256:72ae9ae3a7a6473223589a1621f9001fe802d59ed227fd6a8503c9af67c1d5f4"}, + {file = "pywin32-309-cp39-cp39-win_amd64.whl", hash = "sha256:88bc06d6a9feac70783de64089324568ecbc65866e2ab318eab35da3811fd7ef"}, ] [[package]] @@ -2797,14 +2816,14 @@ files = [ [[package]] name = "virtualenv" -version = "20.29.1" +version = "20.29.3" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "virtualenv-20.29.1-py3-none-any.whl", hash = "sha256:4e4cb403c0b0da39e13b46b1b2476e505cb0046b25f242bee80f62bf990b2779"}, - {file = "virtualenv-20.29.1.tar.gz", hash = "sha256:b8b8970138d32fb606192cb97f6cd4bb644fa486be9308fb9b63f81091b5dc35"}, + {file = "virtualenv-20.29.3-py3-none-any.whl", hash = "sha256:3e3d00f5807e83b234dfb6122bf37cfadf4be216c53a49ac059d02414f819170"}, + {file = "virtualenv-20.29.3.tar.gz", hash = "sha256:95e39403fcf3940ac45bc717597dba16110b74506131845d9b687d5e73d947ac"}, ] [package.dependencies] From c9c2058fb301fd95d33e3899d1d045eae2abe61a Mon Sep 17 00:00:00 2001 From: Ry Jones Date: Sun, 16 Mar 2025 07:32:13 -0700 Subject: [PATCH 37/76] Update changed-files to non vulnerable version (#3591) see https://github.com/advisories/GHSA-mrrh-fwg8-r2c3 Signed-off-by: Ry Jones --- .github/workflows/bdd-integration-tests.yml | 2 +- .github/workflows/bdd-interop-tests.yml | 2 +- .github/workflows/scenario-integration-tests.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/bdd-integration-tests.yml b/.github/workflows/bdd-integration-tests.yml index 2df26f98b9..d8abddb39e 100644 --- a/.github/workflows/bdd-integration-tests.yml +++ b/.github/workflows/bdd-integration-tests.yml @@ -31,7 +31,7 @@ jobs: fetch-depth: 0 - name: Check changed files id: check-changed-files - uses: tj-actions/changed-files@v45 + uses: tj-actions/changed-files@v45.0.9 with: files_yaml: | src: diff --git a/.github/workflows/bdd-interop-tests.yml b/.github/workflows/bdd-interop-tests.yml index 3991902945..3c81e9515d 100644 --- a/.github/workflows/bdd-interop-tests.yml +++ b/.github/workflows/bdd-interop-tests.yml @@ -31,7 +31,7 @@ jobs: fetch-depth: 0 - name: Check changed files id: check-changed-files - uses: tj-actions/changed-files@v45 + uses: tj-actions/changed-files@v45.0.9 with: files_yaml: | src: diff --git a/.github/workflows/scenario-integration-tests.yml b/.github/workflows/scenario-integration-tests.yml index c73a1e187f..d998d36fb2 100644 --- a/.github/workflows/scenario-integration-tests.yml +++ b/.github/workflows/scenario-integration-tests.yml @@ -29,7 +29,7 @@ jobs: fetch-depth: 0 - name: Check changed files id: check-changed-files - uses: tj-actions/changed-files@v45 + uses: tj-actions/changed-files@v45.0.9 with: files_yaml: | scenarios: "scenarios/**/*" From 9c4542d35ec0cb313f0b5d75579a6daf7afed30a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 18:47:05 +0000 Subject: [PATCH 38/76] chore(deps): Bump aiohttp-cors from 0.7.0 to 0.8.0 (#3593) --- poetry.lock | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index d3f3976668..f04835a7b6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -135,18 +135,18 @@ webargs = ">=8.4.0" [[package]] name = "aiohttp-cors" -version = "0.7.0" +version = "0.8.0" description = "CORS support for aiohttp" optional = false python-versions = "*" groups = ["main"] files = [ - {file = "aiohttp-cors-0.7.0.tar.gz", hash = "sha256:4d39c6d7100fd9764ed1caf8cebf0eb01bf5e3f24e2e073fda6234bc48b19f5d"}, - {file = "aiohttp_cors-0.7.0-py3-none-any.whl", hash = "sha256:0451ba59fdf6909d0e2cd21e4c0a43752bc0703d33fc78ae94d9d9321710193e"}, + {file = "aiohttp_cors-0.8.0-py3-none-any.whl", hash = "sha256:b656eeadb84c8fc6771b07460419b100f20dee1d6bf403505b5bd347894c7941"}, + {file = "aiohttp_cors-0.8.0.tar.gz", hash = "sha256:ec70f38432c938e39d240ff38a7d789a5aa0a18087882c12d6cc141eef1144f6"}, ] [package.dependencies] -aiohttp = ">=1.1" +aiohttp = ">=3.9" [[package]] name = "aiosignal" @@ -2973,4 +2973,4 @@ didcommv2 = ["didcomm-messaging"] [metadata] lock-version = "2.1" python-versions = "^3.12" -content-hash = "b476357bba4064d09cd600fd975a732c1483d9071bab6a31e493dedd4aaf272f" +content-hash = "201e717abe0d645784bc5d17bcec506fbb3f55b79d2f4b5a4d89685192690ec4" diff --git a/pyproject.toml b/pyproject.toml index e2531ccd17..a0fa0de0a1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ repository = "https://github.com/openwallet-foundation/acapy" python = "^3.12" aiohttp = "~3.11.12" aiohttp-apispec-acapy = "~3.0.3" -aiohttp-cors = "~0.7.0" +aiohttp-cors = ">=0.7,<0.9" apispec = "^6.6.0" base58 = "~2.1.0" ConfigArgParse = "~1.7" From 0d78dfe55a268dabecaf69a6169dba3e95b3708b Mon Sep 17 00:00:00 2001 From: jamshale <31809382+jamshale@users.noreply.github.com> Date: Mon, 17 Mar 2025 16:01:01 -0700 Subject: [PATCH 39/76] Indicate when interop tests fail (#3592) * Indicate when interop tests fail Signed-off-by: jamshale * Always prepare interop tests Signed-off-by: jamshale * Fix non PR Preperation Signed-off-by: jamshale --------- Signed-off-by: jamshale --- .github/workflows/bdd-interop-tests.yml | 27 ++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/.github/workflows/bdd-interop-tests.yml b/.github/workflows/bdd-interop-tests.yml index 3c81e9515d..1e472caeaa 100644 --- a/.github/workflows/bdd-interop-tests.yml +++ b/.github/workflows/bdd-interop-tests.yml @@ -59,7 +59,7 @@ jobs: with: route: GET /repos/${{ github.event.repository.full_name }}/pulls/${{ github.event.number }} - name: Prepare Interop Tests - if: steps.check-if-src-changed.outputs.run_tests != 'false' + if: (steps.check-if-src-changed.outputs.run_tests != 'false' || steps.check_if_release.outputs.is_release == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') run: | # Get AATH git clone https://github.com/openwallet-foundation/owl-agent-test-harness.git @@ -74,14 +74,31 @@ jobs: cd owl-agent-test-harness ./manage build -a acapy-main - - name: Run PR Interop Tests + - name: Run PR Interop Tests Indy if: (steps.check_if_release.outputs.is_release != 'true' && github.event_name == 'pull_request' && steps.check-if-src-changed.outputs.run_tests != 'false') run: | cd owl-agent-test-harness - NO_TTY=1 LEDGER_URL_CONFIG=http://test.bcovrin.vonx.io TAILS_SERVER_URL_CONFIG=https://tails.vonx.io ./manage run -d acapy-main -t @critical -t ~@wip -t ~@T004-RFC0211 -t ~@DidMethod_orb -t ~@Transport_NoHttpOutbound - - name: Run Release or Nightly Interop Tests + NO_TTY=1 LEDGER_URL_CONFIG=http://test.bcovrin.vonx.io TAILS_SERVER_URL_CONFIG=https://tails.vonx.io ./manage run -d acapy-main -t @critical -t ~@wip -t ~@T004-RFC0211 -t ~@DidMethod_orb -t ~@Transport_NoHttpOutbound -t ~@Anoncreds >> output.txt + - name: Run Release or Nightly Interop Tests Indy + if: (steps.check_if_release.outputs.is_release == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' && steps.check-if-src-changed.outputs.run_tests != 'false') + run: | + cd owl-agent-test-harness + NO_TTY=1 LEDGER_URL_CONFIG=http://test.bcovrin.vonx.io TAILS_SERVER_URL_CONFIG=https://tails.vonx.io ./manage run -d acapy-main -t @critical -t ~@wip -t ~@T004-RFC0211 -t ~@DidMethod_orb -t ~@Transport_NoHttpOutbound -t ~@Anoncreds >> output.txt + - name: Run Release or Nightly Interop Tests Anoncreds if: (steps.check_if_release.outputs.is_release == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' && steps.check-if-src-changed.outputs.run_tests != 'false') run: | cd owl-agent-test-harness - NO_TTY=1 LEDGER_URL_CONFIG=http://test.bcovrin.vonx.io TAILS_SERVER_URL_CONFIG=https://tails.vonx.io ./manage run -d acapy-main -t @AcceptanceTest -t ~@wip -t ~@T004-RFC0211 -t ~@DidMethod_orb -t ~@Transport_NoHttpOutbound + BACKCHANNEL_EXTRA_acapy_main="{\"wallet-type\":\"askar-anoncreds\"}" NO_TTY=1 LEDGER_URL_CONFIG=http://test.bcovrin.vonx.io TAILS_SERVER_URL_CONFIG=https://tails.vonx.io ./manage run -d acapy-main -t @AcceptanceTest -t ~@wip -t ~@T004-RFC0211 -t ~@DidMethod_orb -t ~@Transport_NoHttpOutbound -t ~@Indy -t ~@CredFormat_Indy >> output.txt + - name: Check If Tests Failed + if: steps.check-if-src-changed.outputs.run_tests != 'false' + run: | + cd owl-agent-test-harness + cat output.txt + if grep "Failing scenarios:" output.txt; then + echo "Tests failed" + exit 1 + else + echo "Tests passed" + exit 0 + fi From fc9dfdf8c80461a97951d6f2b116ecc44b009345 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 23:06:08 +0000 Subject: [PATCH 40/76] chore(deps): Bump tj-actions/changed-files in the all-actions group (#3598) Bumps the all-actions group with 1 update: [tj-actions/changed-files](https://github.com/tj-actions/changed-files). Updates `tj-actions/changed-files` from 45.0.9 to 46.0.1 - [Release notes](https://github.com/tj-actions/changed-files/releases) - [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md) - [Commits](https://github.com/tj-actions/changed-files/compare/v45.0.9...v46.0.1) --- updated-dependencies: - dependency-name: tj-actions/changed-files dependency-type: direct:production update-type: version-update:semver-major dependency-group: all-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- .github/workflows/bdd-integration-tests.yml | 2 +- .github/workflows/bdd-interop-tests.yml | 2 +- .github/workflows/scenario-integration-tests.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/bdd-integration-tests.yml b/.github/workflows/bdd-integration-tests.yml index d8abddb39e..5bb7bba4ad 100644 --- a/.github/workflows/bdd-integration-tests.yml +++ b/.github/workflows/bdd-integration-tests.yml @@ -31,7 +31,7 @@ jobs: fetch-depth: 0 - name: Check changed files id: check-changed-files - uses: tj-actions/changed-files@v45.0.9 + uses: tj-actions/changed-files@v46.0.1 with: files_yaml: | src: diff --git a/.github/workflows/bdd-interop-tests.yml b/.github/workflows/bdd-interop-tests.yml index 1e472caeaa..0a979fb02b 100644 --- a/.github/workflows/bdd-interop-tests.yml +++ b/.github/workflows/bdd-interop-tests.yml @@ -31,7 +31,7 @@ jobs: fetch-depth: 0 - name: Check changed files id: check-changed-files - uses: tj-actions/changed-files@v45.0.9 + uses: tj-actions/changed-files@v46.0.1 with: files_yaml: | src: diff --git a/.github/workflows/scenario-integration-tests.yml b/.github/workflows/scenario-integration-tests.yml index d998d36fb2..ff3616e030 100644 --- a/.github/workflows/scenario-integration-tests.yml +++ b/.github/workflows/scenario-integration-tests.yml @@ -29,7 +29,7 @@ jobs: fetch-depth: 0 - name: Check changed files id: check-changed-files - uses: tj-actions/changed-files@v45.0.9 + uses: tj-actions/changed-files@v46.0.1 with: files_yaml: | scenarios: "scenarios/**/*" From 9a4e8ae3c183d2fe2c1c3179254e82a8e72ba926 Mon Sep 17 00:00:00 2001 From: jamshale <31809382+jamshale@users.noreply.github.com> Date: Mon, 17 Mar 2025 16:27:48 -0700 Subject: [PATCH 41/76] Upgrade docker images to release 1.2.4 (#3597) Signed-off-by: jamshale Co-authored-by: Stephen Curran --- demo/docker-agent/Dockerfile.acapy | 2 +- demo/multi-demo/Dockerfile.acapy | 2 +- demo/playground/Dockerfile.acapy | 2 +- demo/playground/README.md | 2 +- docker/Dockerfile.demo | 2 +- docs/features/DIDResolution.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/demo/docker-agent/Dockerfile.acapy b/demo/docker-agent/Dockerfile.acapy index 20e574fa3d..8b9886ddf6 100644 --- a/demo/docker-agent/Dockerfile.acapy +++ b/demo/docker-agent/Dockerfile.acapy @@ -1,4 +1,4 @@ -FROM ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.3 +FROM ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.4 USER root diff --git a/demo/multi-demo/Dockerfile.acapy b/demo/multi-demo/Dockerfile.acapy index 20e574fa3d..8b9886ddf6 100644 --- a/demo/multi-demo/Dockerfile.acapy +++ b/demo/multi-demo/Dockerfile.acapy @@ -1,4 +1,4 @@ -FROM ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.3 +FROM ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.4 USER root diff --git a/demo/playground/Dockerfile.acapy b/demo/playground/Dockerfile.acapy index b427677064..5b3531084a 100644 --- a/demo/playground/Dockerfile.acapy +++ b/demo/playground/Dockerfile.acapy @@ -1,4 +1,4 @@ -FROM ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.3 +FROM ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.4 USER root diff --git a/demo/playground/README.md b/demo/playground/README.md index 534f50eb15..3e7b1a0f25 100644 --- a/demo/playground/README.md +++ b/demo/playground/README.md @@ -26,7 +26,7 @@ These configuration files are provided to the ACA-Py start command via the `AGEN ### Dockerfile and start.sh -[`Dockerfile.acapy`](./Dockerfile.acapy) assembles the image to run. Currently based on [ACA-Py 1.2.0](ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.3), we need [jq](https://stedolan.github.io/jq/) to setup (or not) the ngrok tunnel and execute the Aca-py start command - see [`start.sh`](./start.sh). You may note that the start command is very sparse, additional configuration is done via environment variables in the [docker compose file](./docker-compose.yml). +[`Dockerfile.acapy`](./Dockerfile.acapy) assembles the image to run. Currently based on [ACA-Py 1.2.0](ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.4), we need [jq](https://stedolan.github.io/jq/) to setup (or not) the ngrok tunnel and execute the Aca-py start command - see [`start.sh`](./start.sh). You may note that the start command is very sparse, additional configuration is done via environment variables in the [docker compose file](./docker-compose.yml). ### ngrok diff --git a/docker/Dockerfile.demo b/docker/Dockerfile.demo index e4e9991ab7..7d44dce3ac 100644 --- a/docker/Dockerfile.demo +++ b/docker/Dockerfile.demo @@ -1,4 +1,4 @@ -ARG from_image=ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.3 +ARG from_image=ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.4 FROM ${from_image} ENV ENABLE_PTVSD 0 diff --git a/docs/features/DIDResolution.md b/docs/features/DIDResolution.md index f67e396e88..0d2f360bd4 100644 --- a/docs/features/DIDResolution.md +++ b/docs/features/DIDResolution.md @@ -176,7 +176,7 @@ plugin: The following is a fully functional Dockerfile encapsulating this setup: ```dockerfile= -FROM ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.3 +FROM ghcr.io/openwallet-foundation/acapy-agent:py3.12-1.2.4 RUN pip3 install git+https://github.com/dbluhm/acapy-resolver-github CMD ["aca-py", "start", "-it", "http", "0.0.0.0", "3000", "-ot", "http", "-e", "http://localhost:3000", "--admin", "0.0.0.0", "3001", "--admin-insecure-mode", "--no-ledger", "--plugin", "acapy_resolver_github"] From 8257ff8bcad25d49b66653ed7bd51b5fca20eecc Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Wed, 19 Mar 2025 19:56:04 +0200 Subject: [PATCH 42/76] :bug: Fix auto creation of revocation registries (#3601) * :art: Name args Signed-off-by: ff137 * :sparkles: Move `auto_create_rev_reg` check from handler to initial create Signed-off-by: ff137 * :art: Signed-off-by: ff137 * :white_check_mark: Remove unneeded tests Signed-off-by: ff137 * :art: Name args Signed-off-by: ff137 * :white_check_mark: Test coverage for changes Signed-off-by: ff137 * :art: Format Signed-off-by: ff137 * :art: Fix arg names Signed-off-by: ff137 --------- Signed-off-by: ff137 --- acapy_agent/anoncreds/events.py | 7 +- acapy_agent/anoncreds/issuer.py | 67 +++++--- acapy_agent/anoncreds/revocation_setup.py | 5 +- acapy_agent/anoncreds/routes.py | 2 +- acapy_agent/anoncreds/tests/test_issuer.py | 160 +++++++++++++++++- .../anoncreds/tests/test_revocation_setup.py | 50 +----- 6 files changed, 209 insertions(+), 82 deletions(-) diff --git a/acapy_agent/anoncreds/events.py b/acapy_agent/anoncreds/events.py index 98477bf4e1..719c1d5310 100644 --- a/acapy_agent/anoncreds/events.py +++ b/acapy_agent/anoncreds/events.py @@ -53,7 +53,12 @@ def with_payload( ): """With payload.""" payload = CredDefFinishedPayload( - schema_id, cred_def_id, issuer_id, support_revocation, max_cred_num, options + schema_id=schema_id, + cred_def_id=cred_def_id, + issuer_id=issuer_id, + support_revocation=support_revocation, + max_cred_num=max_cred_num, + options=options, ) return cls(payload) diff --git a/acapy_agent/anoncreds/issuer.py b/acapy_agent/anoncreds/issuer.py index 3d6948cf0e..2bfd1cb490 100644 --- a/acapy_agent/anoncreds/issuer.py +++ b/acapy_agent/anoncreds/issuer.py @@ -21,6 +21,7 @@ from ..core.error import BaseError from ..core.event_bus import Event, EventBus from ..core.profile import Profile +from ..protocols.endorse_transaction.v1_0.util import is_author_role from .base import AnonCredsSchemaAlreadyExists, BaseAnonCredsError from .error_messages import ANONCREDS_PROFILE_REQUIRED_MSG from .events import CredDefFinishedEvent @@ -306,9 +307,22 @@ async def create_and_register_credential_definition( """ options = options or {} - support_revocation = options.get("support_revocation", False) - if not isinstance(support_revocation, bool): - raise ValueError("support_revocation must be a boolean") + support_revocation_option = options.get("support_revocation") + + if support_revocation_option is None: + # Support revocation not set - Default to auto-create rev reg if author role + is_author = is_author_role(self.profile) + auto_create_rev_reg = self.profile.settings.get( + "endorser.auto_create_rev_reg", False + ) + + support_revocation = bool(is_author and auto_create_rev_reg) + else: + # If support_revocation is explicitly set, use that value + if not isinstance(support_revocation_option, bool): + raise ValueError("support_revocation must be a boolean") + + support_revocation = support_revocation_option max_cred_num = options.get("revocation_registry_size", DEFAULT_MAX_CRED_NUM) if not isinstance(max_cred_num, int): @@ -317,7 +331,8 @@ async def create_and_register_credential_definition( # Don't allow revocable cred def to be created without tails server base url if not self.profile.settings.get("tails_server_base_url") and support_revocation: raise AnonCredsIssuerError( - "tails_server_base_url not configured. Can't create revocable credential definition." # noqa: E501 + "tails_server_base_url not configured. " + "Can't create revocable credential definition." ) anoncreds_registry = self.profile.inject(AnonCredsRegistry) @@ -331,31 +346,31 @@ async def create_and_register_credential_definition( ) = await asyncio.get_event_loop().run_in_executor( None, lambda: CredentialDefinition.create( - schema_id, - schema_result.schema.serialize(), - issuer_id, - tag or DEFAULT_CRED_DEF_TAG, - signature_type or DEFAULT_SIGNATURE_TYPE, + schema_id=schema_id, + schema=schema_result.schema.serialize(), + issuer_id=issuer_id, + tag=tag or DEFAULT_CRED_DEF_TAG, + signature_type=signature_type or DEFAULT_SIGNATURE_TYPE, support_revocation=support_revocation, ), ) try: cred_def_result = await anoncreds_registry.register_credential_definition( - self.profile, - schema_result, - CredDef.from_native(cred_def), - options, + profile=self.profile, + schema=schema_result, + credential_definition=CredDef.from_native(cred_def), + options=options, ) await self.store_credential_definition( - schema_result, - cred_def_result, - cred_def_private, - key_proof, - support_revocation, - max_cred_num, - options, + schema_result=schema_result, + cred_def_result=cred_def_result, + cred_def_private=cred_def_private, + key_proof=key_proof, + support_revocation=support_revocation, + max_cred_num=max_cred_num, + options=options, ) return cred_def_result @@ -415,12 +430,12 @@ async def store_credential_definition( if cred_def_result.credential_definition_state.state == STATE_FINISHED: await self.notify( CredDefFinishedEvent.with_payload( - schema_result.schema_id, - identifier, - cred_def_result.credential_definition_state.credential_definition.issuer_id, - support_revocation, - max_cred_num, - options, + schema_id=schema_result.schema_id, + cred_def_id=identifier, + issuer_id=cred_def_result.credential_definition_state.credential_definition.issuer_id, + support_revocation=support_revocation, + max_cred_num=max_cred_num, + options=options, ) ) except AskarError as err: diff --git a/acapy_agent/anoncreds/revocation_setup.py b/acapy_agent/anoncreds/revocation_setup.py index fb50ca9ee6..8714858a11 100644 --- a/acapy_agent/anoncreds/revocation_setup.py +++ b/acapy_agent/anoncreds/revocation_setup.py @@ -67,11 +67,8 @@ def register_events(self, event_bus: EventBus): async def on_cred_def(self, profile: Profile, event: CredDefFinishedEvent): """Handle cred def finished.""" payload = event.payload - auto_create_revocation = is_author_role(profile) and profile.settings.get( - "endorser.auto_create_rev_reg", False - ) - if payload.support_revocation or auto_create_revocation: + if payload.support_revocation: revoc = AnonCredsRevocation(profile) for registry_count in range(self.INITIAL_REGISTRY_COUNT): await revoc.create_and_register_revocation_registry_definition( diff --git a/acapy_agent/anoncreds/routes.py b/acapy_agent/anoncreds/routes.py index a889fa27a4..8d5a37e034 100644 --- a/acapy_agent/anoncreds/routes.py +++ b/acapy_agent/anoncreds/routes.py @@ -187,7 +187,7 @@ async def schemas_post(request: web.BaseRequest): a null value. schema : The schema. If the value of the schema_state.state response field is finished, this field MUST be present and MUST NOT have a null value. - registration_metadata : This field contains metadata about hte registration + registration_metadata : This field contains metadata about the registration process schema_metadata : This fields contains metadata about the schema. diff --git a/acapy_agent/anoncreds/tests/test_issuer.py b/acapy_agent/anoncreds/tests/test_issuer.py index 7442ffd2ae..361e7f794b 100644 --- a/acapy_agent/anoncreds/tests/test_issuer.py +++ b/acapy_agent/anoncreds/tests/test_issuer.py @@ -462,9 +462,167 @@ async def test_create_and_register_credential_definition_invalid_options_raises_ issuer_id="issuer-id", schema_id="schema-id", signature_type="CL", - options={"support_revocation": "100"}, # requires integer + options={"revocation_registry_size": "100"}, # requires integer ) + @mock.patch.object(CredDef, "from_native", return_value=MockCredDefEntry()) + @mock.patch( + "anoncreds.CredentialDefinition.create", + return_value=(mock.MagicMock(), mock.MagicMock(), mock.MagicMock()), + ) + async def test_create_and_register_credential_definition_support_revocation_conditions( + self, mock_cred_def_create, _ + ): + schema_result = GetSchemaResult( + schema_id="schema-id", + schema=AnonCredsSchema( + issuer_id="issuer-id", + name="schema-name", + version="1.0", + attr_names=["attr1", "attr2"], + ), + schema_metadata={}, + resolution_metadata={}, + ) + + cred_def_result = CredDefResult( + job_id="job-id", + credential_definition_state=CredDefState( + state="finished", + credential_definition=CredDef( + issuer_id="did:sov:3avoBCqDMFHFaKUHug9s8W", + schema_id="schema-id", + tag="tag", + type="CL", + value=CredDefValue( + primary=CredDefValuePrimary("n", "s", {}, "rctxt", "z") + ), + ), + credential_definition_id="cred-def-id", + ), + credential_definition_metadata={}, + registration_metadata={}, + ) + + self.profile.inject = mock.Mock( + return_value=mock.MagicMock( + get_schema=mock.CoroutineMock(return_value=schema_result), + register_credential_definition=mock.CoroutineMock( + return_value=cred_def_result + ), + ) + ) + + # Configure author role and auto create rev reg -- expectation: support revocation is True when not specified + self.profile.settings.set_value("endorser.author", True) + self.profile.settings.set_value("endorser.auto_create_rev_reg", True) + + # First assert AnonCredsIssuerError if tails_server_base_url is not set + with self.assertRaises(test_module.AnonCredsIssuerError) as exc: + await self.issuer.create_and_register_credential_definition( + issuer_id="issuer-id", + schema_id="schema-id", + signature_type="CL", + tag="tag", + ) + assert ( + str(exc.exception.message) + == "tails_server_base_url not configured. Can't create revocable credential definition." + ) + + # Now, set the tails_server_base_url + self.profile.settings.set_value("tails_server_base_url", "https://example.com") + + for support_revocation in [True, False, None]: + # Mock the store_credential_definition method + with mock.patch.object( + self.issuer, "store_credential_definition" + ) as mock_store_cred_def: + # Reset the mocks for each iteration + mock_cred_def_create.reset_mock() + mock_store_cred_def.reset_mock() + + await self.issuer.create_and_register_credential_definition( + issuer_id="issuer-id", + schema_id="schema-id", + signature_type="CL", + tag="tag", + options={"support_revocation": support_revocation}, + ) + + # Check if support_revocation is True when None or True was passed + expected_support_revocation = ( + support_revocation if support_revocation is not None else True + ) + + # Assert CredentialDefinition.create call was made with correct support_revocation value + mock_cred_def_create.assert_called_once_with( + schema_id="schema-id", + schema=schema_result.schema.serialize(), + issuer_id="issuer-id", + tag="tag", + signature_type="CL", + support_revocation=expected_support_revocation, + ) + + # Assert store_credential_definition call args + mock_store_cred_def.assert_called_once_with( + schema_result=schema_result, + cred_def_result=mock.ANY, + cred_def_private=mock.ANY, + key_proof=mock.ANY, + support_revocation=expected_support_revocation, + max_cred_num=mock.ANY, + options=mock.ANY, + ) + + # Now, disable author role and auto create rev reg -- expectation: support revocation is False when not specified + self.profile.settings.set_value("endorser.author", False) + self.profile.settings.set_value("endorser.auto_create_rev_reg", False) + + for support_revocation in [True, False, None]: + # Mock the CredentialDefinition.create call, and the store_credential_definition method + with mock.patch.object( + self.issuer, "store_credential_definition" + ) as mock_store_cred_def: + # Reset the mock for each iteration + mock_cred_def_create.reset_mock() + mock_store_cred_def.reset_mock() + + await self.issuer.create_and_register_credential_definition( + issuer_id="issuer-id", + schema_id="schema-id", + signature_type="CL", + tag="tag", + options={"support_revocation": support_revocation}, + ) + + # Check if support_revocation is False when set to None + expected_support_revocation = ( + support_revocation if support_revocation is not None else False + ) + + # Assert CredentialDefinition.create call was made with correct support_revocation value + mock_cred_def_create.assert_called_once_with( + schema_id="schema-id", + schema=schema_result.schema.serialize(), + issuer_id="issuer-id", + tag="tag", + signature_type="CL", + support_revocation=expected_support_revocation, + ) + + # Assert store_credential_definition call args + mock_store_cred_def.assert_called_once_with( + schema_result=schema_result, + cred_def_result=mock.ANY, + cred_def_private=mock.ANY, + key_proof=mock.ANY, + support_revocation=expected_support_revocation, + max_cred_num=mock.ANY, + options=mock.ANY, + ) + @mock.patch.object(test_module.AnonCredsIssuer, "notify") async def test_create_and_register_credential_definition_finishes(self, mock_notify): self.profile.inject = mock.Mock( diff --git a/acapy_agent/anoncreds/tests/test_revocation_setup.py b/acapy_agent/anoncreds/tests/test_revocation_setup.py index 357899f4c9..57f4aab04f 100644 --- a/acapy_agent/anoncreds/tests/test_revocation_setup.py +++ b/acapy_agent/anoncreds/tests/test_revocation_setup.py @@ -53,55 +53,7 @@ async def test_on_cred_def_support_revocation_registers_revocation_def( "create_and_register_revocation_registry_definition", return_value=None, ) - async def test_on_cred_def_author_with_auto_create_rev_reg_config_registers_reg_def( - self, mock_register_revocation_registry_definition - ): - self.profile.settings["endorser.author"] = True - self.profile.settings["endorser.auto_create_rev_reg"] = True - event = CredDefFinishedEvent( - CredDefFinishedPayload( - schema_id="schema_id", - cred_def_id="cred_def_id", - issuer_id="issuer_id", - support_revocation=False, - max_cred_num=100, - options={}, - ) - ) - await self.revocation_setup.on_cred_def(self.profile, event) - - assert mock_register_revocation_registry_definition.called - - @mock.patch.object( - AnonCredsRevocation, - "create_and_register_revocation_registry_definition", - return_value=None, - ) - async def test_on_cred_def_author_with_auto_create_rev_reg_config_and_support_revoc_option_registers_reg_def( - self, mock_register_revocation_registry_definition - ): - self.profile.settings["endorser.author"] = True - self.profile.settings["endorser.auto_create_rev_reg"] = True - event = CredDefFinishedEvent( - CredDefFinishedPayload( - schema_id="schema_id", - cred_def_id="cred_def_id", - issuer_id="issuer_id", - support_revocation=True, - max_cred_num=100, - options={}, - ) - ) - await self.revocation_setup.on_cred_def(self.profile, event) - - assert mock_register_revocation_registry_definition.called - - @mock.patch.object( - AnonCredsRevocation, - "create_and_register_revocation_registry_definition", - return_value=None, - ) - async def test_on_cred_def_not_author_or_support_rev_option( + async def test_on_cred_def_not_support_rev_option( self, mock_register_revocation_registry_definition ): event = CredDefFinishedEvent( From 2c8629aaefd880c69f49dcb468951d75ecad1d25 Mon Sep 17 00:00:00 2001 From: Yuki I <42908250+MonolithicMonk@users.noreply.github.com> Date: Wed, 19 Mar 2025 14:11:20 -0500 Subject: [PATCH 43/76] fix: support askar-anoncreds backend in multi-ledger configuration (#3603) Signed-off-by: Yuki I Co-authored-by: Yuki I Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- .../ledger/multiple_ledger/manager_provider.py | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 47c6a257e3..ae43b0525c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,8 +12,8 @@ repos: hooks: # Run the linter - id: ruff - stages: [commit] + stages: [pre-commit] args: [--fix, --exit-non-zero-on-fix, "--config", "pyproject.toml"] # Run the formatter - id: ruff-format - stages: [commit] + stages: [pre-commit] diff --git a/acapy_agent/ledger/multiple_ledger/manager_provider.py b/acapy_agent/ledger/multiple_ledger/manager_provider.py index bfb13de923..052065993f 100644 --- a/acapy_agent/ledger/multiple_ledger/manager_provider.py +++ b/acapy_agent/ledger/multiple_ledger/manager_provider.py @@ -18,7 +18,7 @@ class MultiIndyLedgerManagerProvider(BaseProvider): """Multiple Indy ledger support manager provider.""" MANAGER_TYPES = { - "askar-profile": ( + "single-wallet-askar": ( DeferLoad( "acapy_agent.ledger.multiple_ledger." "indy_vdr_manager.MultiIndyVDRLedgerManager" @@ -26,7 +26,7 @@ class MultiIndyLedgerManagerProvider(BaseProvider): ), } LEDGER_TYPES = { - "askar-profile": { + "single-wallet-askar": { "pool": DeferLoad("acapy_agent.ledger.indy_vdr.IndyVdrLedgerPool"), "ledger": DeferLoad("acapy_agent.ledger.indy_vdr.IndyVdrLedger"), }, @@ -40,12 +40,11 @@ def __init__(self, root_profile): def provide(self, settings: BaseSettings, injector: BaseInjector): """Create the multiple Indy ledger manager instance.""" - if self.root_profile.BACKEND_NAME == "askar": - manager_type = "askar-profile" + backend_name = self.root_profile.BACKEND_NAME + if backend_name in ("askar", "askar-anoncreds"): + manager_type = "single-wallet-askar" else: - raise MultipleLedgerManagerError( - f"Unexpected wallet backend: {self.root_profile.BACKEND_NAME}" - ) + raise MultipleLedgerManagerError(f"Unexpected wallet backend: {backend_name}") if manager_type not in self._inst: manager_class = self.MANAGER_TYPES.get(manager_type) From e0f778abe8e48b2de1c4f8391203363d5458f1cb Mon Sep 17 00:00:00 2001 From: jamshale <31809382+jamshale@users.noreply.github.com> Date: Thu, 20 Mar 2025 11:02:50 -0700 Subject: [PATCH 44/76] Repair BDD integration release tests (#3605) * Repair BDD integration release tests Signed-off-by: jamshale * Remove a few more mediation tests Signed-off-by: jamshale * Remove Failing tag Signed-off-by: jamshale * Add back function to agent_container Signed-off-by: jamshale --------- Signed-off-by: jamshale --- demo/features/0453-issue-credential.feature | 11 ----------- demo/features/0586-sign-transaction.feature | 4 ---- demo/runners/agent_container.py | 4 ++-- 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/demo/features/0453-issue-credential.feature b/demo/features/0453-issue-credential.feature index 4f9b47e46d..db7955dbba 100644 --- a/demo/features/0453-issue-credential.feature +++ b/demo/features/0453-issue-credential.feature @@ -17,13 +17,6 @@ Feature: RFC 0453 Aries agent issue credential | Acme_capabilities | Bob_capabilities | Schema_name | Credential_data | Acme_extra | Bob_extra | | --public-did --did-exchange | --did-exchange | driverslicense | Data_DL_NormalizedValues | | | - @Release @WalletType_Askar @AltTests - Examples: - | Acme_capabilities | Bob_capabilities | Schema_name | Credential_data | Acme_extra | Bob_extra | - | --public-did | | driverslicense | Data_DL_NormalizedValues | | | - | --public-did --mediation | --mediation | driverslicense | Data_DL_NormalizedValues | | | - | --public-did --multitenant | --multitenant --log-file | driverslicense | Data_DL_NormalizedValues | | | - @Release @WalletType_Askar_AnonCreds @BasicTest @cred_type_vc_di Examples: | Acme_capabilities | Bob_capabilities | Schema_name | Credential_data | Acme_extra | Bob_extra | @@ -208,10 +201,8 @@ Feature: RFC 0453 Aries agent issue credential Examples: | Acme_capabilities | Bob_capabilities | Schema_name | Credential_data | Key_type | Sig_type | | --public-did --cred-type json-ld --did-exchange | --did-exchange | driverslicense | Data_DL_NormalizedValues | ed25519 | Ed25519Signature2018 | - | --public-did --cred-type json-ld --mediation | --mediation | driverslicense | Data_DL_NormalizedValues | ed25519 | Ed25519Signature2018 | | --public-did --cred-type json-ld --multitenant --log-file | --multitenant | driverslicense | Data_DL_NormalizedValues | ed25519 | Ed25519Signature2018 | | --public-did --cred-type json-ld --did-exchange | --did-exchange | driverslicense | Data_DL_NormalizedValues | ed25519 | Ed25519Signature2020 | - | --public-did --cred-type json-ld --mediation | --mediation | driverslicense | Data_DL_NormalizedValues | ed25519 | Ed25519Signature2020 | | --public-did --cred-type json-ld --multitenant --log-file | --multitenant | driverslicense | Data_DL_NormalizedValues | ed25519 | Ed25519Signature2020 | @Release @WalletType_Askar @BBS @@ -277,10 +268,8 @@ Feature: RFC 0453 Aries agent issue credential Examples: | Acme_capabilities | Bob_capabilities | Schema_name | Credential_data | Key_type | Sig_type | | --public-did --cred-type json-ld --did-exchange | --did-exchange | driverslicense | Data_DL_NormalizedValues | ed25519 | Ed25519Signature2018 | - | --public-did --cred-type json-ld --mediation | --mediation | driverslicense | Data_DL_NormalizedValues | ed25519 | Ed25519Signature2018 | | --public-did --cred-type json-ld --multitenant | --multitenant | driverslicense | Data_DL_NormalizedValues | ed25519 | Ed25519Signature2018 | | --public-did --cred-type json-ld --did-exchange | --did-exchange | driverslicense | Data_DL_NormalizedValues | ed25519 | Ed25519Signature2020 | - | --public-did --cred-type json-ld --mediation | --mediation | driverslicense | Data_DL_NormalizedValues | ed25519 | Ed25519Signature2020 | | --public-did --cred-type json-ld --multitenant | --multitenant | driverslicense | Data_DL_NormalizedValues | ed25519 | Ed25519Signature2020 | @Release @WalletType_Askar @BBS diff --git a/demo/features/0586-sign-transaction.feature b/demo/features/0586-sign-transaction.feature index 7fc2198115..3f30025804 100644 --- a/demo/features/0586-sign-transaction.feature +++ b/demo/features/0586-sign-transaction.feature @@ -23,9 +23,7 @@ Feature: RFC 0586 Aries sign (endorse) transactions functions Examples: | Acme_capabilities | Bob_capabilities | Schema_name | | --did-exchange | --did-exchange | driverslicense | - | --mediation | --mediation | driverslicense | | --multitenant | --multitenant | driverslicense | - | --mediation --multitenant | --mediation --multitenant | driverslicense | @TODO @Mulitledger Examples: @@ -110,8 +108,6 @@ Feature: RFC 0586 Aries sign (endorse) transactions functions Examples: | Acme_capabilities | Bob_capabilities | Schema_name | Credential_data | | --revocation --public-did --did-exchange | --revocation --did-exchange | driverslicense | Data_DL_NormalizedValues | - | --revocation --public-did --mediation | --revocation --mediation | driverslicense | Data_DL_NormalizedValues | - | --revocation --public-did --mediation --multitenant | --revocation --mediation --multitenant | driverslicense | Data_DL_NormalizedValues | @Mulitledger Examples: diff --git a/demo/runners/agent_container.py b/demo/runners/agent_container.py index 305689f1c6..83fdfcb1b5 100644 --- a/demo/runners/agent_container.py +++ b/demo/runners/agent_container.py @@ -394,7 +394,7 @@ async def handle_present_proof(self, message): if credentials: for row in sorted( credentials, - key=lambda c: int(c["cred_info"]["attrs"]["timestamp"]), + key=lambda c: int(c["cred_info"]["attrs"].get("timestamp", 0)), reverse=True, ): for referent in row["presentation_referents"]: @@ -500,7 +500,7 @@ async def handle_present_proof_v2_0(self, message): sorted_creds = sorted( creds, key=lambda c: int( - c["cred_info"]["attrs"]["timestamp"] + c["cred_info"]["attrs"].get("timestamp", 0) ), reverse=True, ) From 76ac265c9c29818facf32fcb3513957ff729d3f1 Mon Sep 17 00:00:00 2001 From: Stephen Curran Date: Thu, 20 Mar 2025 13:51:38 -0700 Subject: [PATCH 45/76] 1.3.0rc0 (#3604) * 1.3.0rc0 Signed-off-by: Stephen Curran * Additional Changelog notes Signed-off-by: Stephen Curran * Add PR to the list Signed-off-by: Stephen Curran * Adjustments to the API changes section Signed-off-by: Stephen Curran --------- Signed-off-by: Stephen Curran --- CHANGELOG.md | 302 +++++++-- Managing-ACA-Py-Doc-Site.md | 4 +- PUBLISHING.md | 4 +- README.md | 4 +- docs/conf.py | 5 +- docs/features/SupportedRFCs.md | 12 +- docs/index.rst | 2 +- open-api/openapi.json | 1123 ++++++++++++++++---------------- open-api/swagger.json | 924 +++++++++++--------------- pyproject.toml | 2 +- 10 files changed, 1246 insertions(+), 1136 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73dad664e9..9290db9234 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,185 @@ # Aries Cloud Agent Python Changelog +## 1.3.0rc0 + +### March 20, 2025 + +Release 1.3.0 is a significant release that adds many updates, fixes and an important breaking change (starting to remove support for [AIP 1.0] from ACA-Py) from the 1.2.LTS branch of ACA-Py. The full list of changes are in in the [categorized list of pull requests](#130-categorized-list-of-pull-requests) for the release. As always, ACA-Py remains fully up to date with its dependencies. Fixes and improvements focused around the latest wallet type (`askar-anoncreds`), AnonCreds processing in general, and AnonCreds revocation in particular. + +### 1.3.0 Deprecation Notices + +- In the next ACA-Py release, we will be dropping from the core ACA-Py repository the AIP 1.0 [RFC 0037 Issue Credentials v1.0] and [RFC 0037 Present Proof v1.0] DIDComm protocols. Each of the protocols will be moved to the [ACA-Py Plugins] repo. All ACA-Py implementers that use those protocols **SHOULD** update as soon as possible to the [AIP 2.0] versions of those protocols ([RFC 0453 Issue Credential v2.0] and [RFC 0454 Present Proof v2.0], respectively). Once the protocols are removed from ACA-Py, anyone still using those protocols **MUST** adjust their configuration to load those protocols from the respective plugins. + +[ACA-Py Plugins]: https://plugins.aca-py.org +[RFC 0160 Connections]: https://identity.foundation/aries-rfcs/latest/features/0160-connection-protocol/ +[RFC 0037 Issue Credentials v1.0]: https://identity.foundation/aries-rfcs/latest/features/0036-issue-credential/ +[RFC 0037 Present Proof v1.0]: https://identity.foundation/aries-rfcs/latest/features/0037-present-proof/ +[AIP 1.0]: https://github.com/decentralized-identity/aries-rfcs/tree/main/concepts/0302-aries-interop-profile#aries-interop-profile-version-10 +[AIP 2.0]: https://identity.foundation/aries-rfcs/latest/aip2/0003-protocols/ +[RFC 0434 Out of Band]: https://identity.foundation/aries-rfcs/latest/aip2/0434-outofband/ +[RFC 0023 DID Exchange]: https://identity.foundation/aries-rfcs/latest/aip2/0023-did-exchange/ +[RFC 0453 Issue Credential v2.0]: https://identity.foundation/aries-rfcs/latest/aip2/0453-issue-credential-v2/ +[RFC 0454 Present Proof v2.0]: https://identity.foundation/aries-rfcs/latest/aip2/0454-present-proof-v2/ +[Connections Protocol Plugin]: https://plugins.aca-py.org/latest/connections/ + +### 1.3.0 Breaking Changes + +In this release, the DiDComm [RFC 0160 Connections] is removed, in favour of the newer, more complete [RFC 0434 Out of Band] and [RFC 0023 DID Exchange]. Those still requiring [RFC 0160 Connections] protocol support must update their startup parameters to include the [Connections Protocol Plugin]. See the documentation for details, but once the ACA-Py instance startup options are extended to include the Connections protocol plugin, Controllers using the Connections protocol should continue to work as they had been. That said, we highly recommend implementers move to the [RFC 0434 Out of Band] and [RFC 0023 DID Exchange] Protocols as soon as possible. + +### 1.3.0 ACA-Py Controller API Changes: + +- Added: `did:indy` support, including a new `POST /did/indy/create` endpoint +- Routes that support pagination (such as endpoints for fetching connections or credential/presentation exchange records), now include `descending` as an optional query parameter. +- `validFrom` and `validUntil` added to the `Credential` and `VerifiableCredential` objects + +Specifics of the majority of the can be found by looking at the diffs for the `swagger.json` and `openapi.json` files that are part of the [1.3.0.rc Release Pull Request](https://github.com/openwallet-foundation/acapy/pull/3604). Later pull requests might introduce some additional changes. + +### 1.3.0 Categorized List of Pull Requests + +- Updates/fixes to wallet types -- `askar` and `askar-anoncreds` + - fix: Support askar-anoncreds backend in multi-ledger configuration [\#3603](https://github.com/openwallet-foundation/acapy/pull/3603) [MonolithicMonk](https://github.com/MonolithicMonk) + - :bug: Fix: allow anoncreds wallet to delete indy credentials [\#3551](https://github.com/openwallet-foundation/acapy/pull/3551) [ff137](https://github.com/ff137) + - :bug: Fix: allow multitenant askar-anoncreds wallets to present indy credentials [\#3549](https://github.com/openwallet-foundation/acapy/pull/3549) [ff137](https://github.com/ff137) + - fix: ensure profile names are unique [\#3470](https://github.com/openwallet-foundation/acapy/pull/3470) [dbluhm](https://github.com/dbluhm) + - feat: add did management design doc [\#3375](https://github.com/openwallet-foundation/acapy/pull/3375) [dbluhm](https://github.com/dbluhm) + - Add did:indy transaction version 2 support [\#3253](https://github.com/openwallet-foundation/acapy/pull/3253) [jamshale](https://github.com/jamshale) + - :art: Deprecate count/start query params and implement limit/offset [\#3208](https://github.com/openwallet-foundation/acapy/pull/3208) [ff137](https://github.com/ff137) + - :sparkles: Add ordering options to askar scan and fetch_all methods [\#3173](https://github.com/openwallet-foundation/acapy/pull/3173) [ff137](https://github.com/ff137) +- Updates/fixes to AnonCreds Processing + - :bug: Fix auto creation of revocation registries [\#3601](https://github.com/openwallet-foundation/acapy/pull/3601) [ff137](https://github.com/ff137) + - :sparkles: Refactor TailsServer injection pattern [\#3587](https://github.com/openwallet-foundation/acapy/pull/3587) [ff137](https://github.com/ff137) + - :bug: Fix: Register both askar and anoncreds plugins for multitenancy [\#3585](https://github.com/openwallet-foundation/acapy/pull/3585) [ff137](https://github.com/ff137) + - Repair anoncreds holder revocation list request [\#3570](https://github.com/openwallet-foundation/acapy/pull/3570) [jamshale](https://github.com/jamshale) + - Anoncreds proof validation issue (once credential has been revoked) [\#3557](https://github.com/openwallet-foundation/acapy/pull/3557) [ianco](https://github.com/ianco) + - Fix revocation accum sync when endorsement txn fails [\#3547](https://github.com/openwallet-foundation/acapy/pull/3547) [jamshale](https://github.com/jamshale) + - Allow schema id to be used during anoncreds issuance [\#3497](https://github.com/openwallet-foundation/acapy/pull/3497) [jamshale](https://github.com/jamshale) + - Fix Class import for AnonCreds Registry routes [\#3495](https://github.com/openwallet-foundation/acapy/pull/3495) [PatStLouis](https://github.com/PatStLouis) + - fix typo in error message of indy credential offer [\#3485](https://github.com/openwallet-foundation/acapy/pull/3485) [zoblazo](https://github.com/zoblazo) + - Fixing BaseAnonCredsResolver get_revocation_list abstract method [\#3484](https://github.com/openwallet-foundation/acapy/pull/3484) [thiagoromanos](https://github.com/thiagoromanos) + - Anoncreds Issuance - Extra options. [\#3483](https://github.com/openwallet-foundation/acapy/pull/3483) [jamshale](https://github.com/jamshale) +- Multi-Tenancy Related Updates and Fixes: + - fix: tenant access to endpoints leading to access the base wallet [\#3545](https://github.com/openwallet-foundation/acapy/pull/3545) [thiagoromanos](https://github.com/thiagoromanos) + - fix: connection reuse with multi-tenancy [\#3543](https://github.com/openwallet-foundation/acapy/pull/3543) [dbluhm](https://github.com/dbluhm) + - Remove base wallet type must be new wallet type restriction [\#3542](https://github.com/openwallet-foundation/acapy/pull/3542) [jamshale](https://github.com/jamshale) +- Logging and Error Handling Updates and Fixes: + - :art: Include the validation error in Unprocessable Entity reason [\#3517](https://github.com/openwallet-foundation/acapy/pull/3517) [ff137](https://github.com/ff137) + - Catch and log universal resolver setup error [\#3511](https://github.com/openwallet-foundation/acapy/pull/3511) [jamshale](https://github.com/jamshale) +- W3C Verifiable Credentials Support Updates and Fixes: + - Add vcdm 2.0 model and context [\#3436](https://github.com/openwallet-foundation/acapy/pull/3436) [PatStLouis](https://github.com/PatStLouis) +- DIDComm Protocol Updates and Fixes: + - BREAKING: remove connection protocol [\#3184](https://github.com/openwallet-foundation/acapy/pull/3184) [dbluhm](https://github.com/dbluhm) +- Documentation and Tutorial Pull Requests: + - :memo: Update README [\#3588](https://github.com/openwallet-foundation/acapy/pull/3588) [ff137](https://github.com/ff137) + - Fix missing log_timer import in acme.py [\#3562](https://github.com/openwallet-foundation/acapy/pull/3562) [parth5805](https://github.com/parth5805) + - Fix prompt for alice/faber demo [\#3553](https://github.com/openwallet-foundation/acapy/pull/3553) [ianco](https://github.com/ianco) + - Add reuse document to MkDocs YML to add to doc site [\#3535](https://github.com/openwallet-foundation/acapy/pull/3535) [swcurran](https://github.com/swcurran) + - Create ReuseConnection.md [\#3534](https://github.com/openwallet-foundation/acapy/pull/3534) [MonolithicMonk](https://github.com/MonolithicMonk) + - :white_check_mark: Fix demo playground example tests [\#3531](https://github.com/openwallet-foundation/acapy/pull/3531) [ff137](https://github.com/ff137) + - :arrow_up: Upgrade sphinx versions in docs [\#3530](https://github.com/openwallet-foundation/acapy/pull/3530) [ff137](https://github.com/ff137) +- ACA-Py Testing Pull Requests: + - Repair BDD integration release tests [\#3605](https://github.com/openwallet-foundation/acapy/pull/3605) [jamshale](https://github.com/jamshale) + - Indicate when interop tests fail [\#3592](https://github.com/openwallet-foundation/acapy/pull/3592) [jamshale](https://github.com/jamshale) + - :zap: Automatically use pytest-xdist to run tests in parallel [\#3574](https://github.com/openwallet-foundation/acapy/pull/3574) [ff137](https://github.com/ff137) + - :arrow_up: Upgrade poetry to 2.1 [\#3538](https://github.com/openwallet-foundation/acapy/pull/3538) [ff137](https://github.com/ff137) + - :zap: Remove `--cov` from pytest.ini_options [\#3522](https://github.com/openwallet-foundation/acapy/pull/3522) [ff137](https://github.com/ff137) + - :heavy_plus_sign: Re-add `git` to Dockerfile [\#3515](https://github.com/openwallet-foundation/acapy/pull/3515) [ff137](https://github.com/ff137) + - Restore connection route tests [\#3461](https://github.com/openwallet-foundation/acapy/pull/3461) [dbluhm](https://github.com/dbluhm) +- Dependency Management pull requests (other than Dependabot): + - Upgrade docker images to release 1.2.4 [\#3597](https://github.com/openwallet-foundation/acapy/pull/3597) [jamshale](https://github.com/jamshale) + - Update changed-files to non vulnerable version [\#3591](https://github.com/openwallet-foundation/acapy/pull/3591) [ryjones](https://github.com/ryjones) + - :arrow_up: Update lock file [\#3590](https://github.com/openwallet-foundation/acapy/pull/3590) [ff137](https://github.com/ff137) + - :arrow_up: Upgrade ruff to 0.11 [\#3589](https://github.com/openwallet-foundation/acapy/pull/3589) [ff137](https://github.com/ff137) + - Update acapy images to 1.2.3 [\#3571](https://github.com/openwallet-foundation/acapy/pull/3571) [jamshale](https://github.com/jamshale) + - :construction_worker: Dependabot: don't ignore major releases [\#3521](https://github.com/openwallet-foundation/acapy/pull/3521) [ff137](https://github.com/ff137) + - Grouped upgrades - Week 7, 2025 [\#3508](https://github.com/openwallet-foundation/acapy/pull/3508) [jamshale](https://github.com/jamshale) + - Upgrade to bookworm [\#3498](https://github.com/openwallet-foundation/acapy/pull/3498) [jamshale](https://github.com/jamshale) + - Update aries-askar / Generate poetry.lock with poetry 2.0 [\#3478](https://github.com/openwallet-foundation/acapy/pull/3478) [jamshale](https://github.com/jamshale) + - Upgrade askar and did_webvh [\#3474](https://github.com/openwallet-foundation/acapy/pull/3474) [jamshale](https://github.com/jamshale) + - Update dockerfile image after release [\#3469](https://github.com/openwallet-foundation/acapy/pull/3469) [jamshale](https://github.com/jamshale) + - :arrow_up: Upgrade dependencies [\#3455](https://github.com/openwallet-foundation/acapy/pull/3455) [ff137](https://github.com/ff137) +- Release management pull requests: + - 1.3.0rc0 [\#3604](https://github.com/openwallet-foundation/acapy/pull/3604) [swcurran](https://github.com/swcurran) +- Dependabot PRs + - [Link to list of Dependabot PRs in this release](https://github.com/openwallet-foundation/acapy/pulls?q=is%3Apr+is%3Amerged+merged%3A2025-01-21..2025-03-19+author%3Aapp%2Fdependabot+) + +## 1.2.4 + +### March 13, 2025 + +This patch release addresses three bugs backported from the `main` branch: + +- Fixes a problem in the handling of connection reuse in multitenancy environments. This is a backport of the PR [fix: connection reuse with multi-tenancy #3543](https://github.com/openwallet-foundation/acapy/pull/3543). This fixes the issue when using multi-tenancy, calls to `POST /out-of-band/receive-invitation?use_existing_connection=true` failing with a record not found error, despite connection reuse actually being completed in the background. +- Fixes a problem when using acapy with multitenant enabled and admin-insecure-mode. Without this fix, tenant endpoints (like `GET /wallet/did` for example) could be accessed without a bearer token. For details see: [fix: tenant access to endpoints leading to access the base wallet #3545](https://github.com/openwallet-foundation/acapy/pull/3545). +- Fixes the AnonCreds holder revocation list endpoint which was erroneously using the `to` timestamp for the `from`, preventing the creation of valid non-revocation proofs. For details, see: [Repair anoncreds holder revocation list request](https://github.com/openwallet-foundation/acapy/pull/3570) + +### 1.2.4 Deprecation Notices + +The same **[deprecation notices](#101-deprecation-notices)** from the [1.1.0](#110) release about AIP 1.0 protocols still apply. The protocols remain in this 1.2.4 release, but the Connections Protocol has been removed from the ACA-Py `main` branch, and is available as a [plugin](https://github.com/openwallet-foundation/acapy-plugins/tree/main/connections). The Issue Credential v1 and Present Proof v1 protocols will soon be changed similarly. Please review these notifications carefully! + +### 1.2.4 Breaking Changes + +There are no breaking changes in this release. + +### 1.2.4 Categorized List of Pull Requests + +- AnonCreds Revocation Fixes + - 1.2.LTS Repair anoncreds holder revocation list request [\#3580](https://github.com/openwallet-foundation/acapy/pull/3580) [jamshale](https://github.com/jamshale) +- Multitenant Fixes + - fix: cherry-pick fixes from main to 1.2.lts [\#3577](https://github.com/openwallet-foundation/acapy/pull/3577) [thiagoromanos](https://github.com/thiagoromanos) + +- Release management pull requests: + - 1.2.4 [\#3582](https://github.com/openwallet-foundation/acapy/pull/3582) [swcurran](https://github.com/swcurran) + +## 1.2.3 + +### March 6, 2025 + +This patch release addresses a bug in the publishing of AnonCreds revocation entries that caused the ledger and issuer wallet to become out of sync. As a result, revoked credentials were not being correctly flagged as revoked when presented. Previously, this issue was mitigated by an automatic “sync-revocation” process, which generally resolved the problem. However, we recently identified scenarios where the presence of an Indy Endorser in the revocation publication flow caused the “sync-revocation” process to fail silently. + +This patch resolves that issue. Once applied, if a revocation batch results in an out-of-sync state, the “sync-revocation” process will automatically run to correct it. + +For more details, see [Issue 3546](https://github.com/openwallet-foundation/acapy/issues/3546). + +### 1.2.3 Deprecation Notices + +The same **[deprecation notices](#101-deprecation-notices)** from the [1.1.0](#110) release about AIP 1.0 protocols still apply. The protocols remain in this 1.2.3 release, but the Connections Protocol has been removed from the ACA-Py `main` branch, and is available as a [plugin](https://github.com/openwallet-foundation/acapy-plugins/tree/main/connections). The Issue Credential v1 and Present Proof v1 protocols will soon be changed similarly. Please review these notifications carefully! + +### 1.2.3 Breaking Changes + +There are no breaking changes in this release. + +### 1.2.3 Categorized List of Pull Requests + +- AnonCreds Revocation Fixes + - 1.2.LTS Fix revocation accum sync when endorsement txn fails (#3547) [\#3555](https://github.com/openwallet-foundation/acapy/pull/3555) [jamshale](https://github.com/jamshale) + +- Release management pull requests: + - 1.2.3 [\#3559](https://github.com/openwallet-foundation/acapy/pull/3559) [swcurran](https://github.com/swcurran) + +## 1.2.2 + +### January 30, 2025 + +A patch release to upgrade [Askar](https://github.com/openwallet-foundation/askar) to [0.4.3](https://github.com/openwallet-foundation/askar/releases/tag/v0.4.3) and fixes a problem with wallet names in a multitenant, single-wallet configuration. + +Addresses the problem outlined in [#3471](https://github.com/openwallet-foundation/acapy/issues/3471) around profiles in multi-tenant/single wallet deployments. The update to Askar addresses an intermittent hang on startup, and a dependency change that can result in a substantial performance improvement in some cases. See issues: [openwallet-foundation/askar#350](https://github.com/openwallet-foundation/askar/pull/350), [openwallet-foundation/askar#351](https://github.com/openwallet-foundation/askar/pull/351), [openwallet-foundation/askar#354](https://github.com/openwallet-foundation/askar/pull/354). This [comment on one of the PRs](https://github.com/openwallet-foundation/askar/pull/350#issuecomment-2615727109) describes the scenario where a substantial performance improvement was seen as a result of the change in Askar. + +### 1.2.2 Deprecation Notices + +The same **[deprecation notices](#101-deprecation-notices)** from the [1.1.0](#110) release about AIP 1.0 protocols still apply. The protocols remain in the 1.2.2 release, but will be moved out of the core and into plugins soon. Please review these notifications carefully! + +### 1.2.2 Breaking Changes + +There are no breaking changes in this release. + +### 1.2.2 Categorized List of Pull Requests + +- Startup, Wallet, and Upgrade Fixes + - 1.2 LTS: Askar upgrade and fix profile unique names [\#3477](https://github.com/openwallet-foundation/acapy/pull/3477) [jamshale](https://github.com/jamshale) + +- Release management pull requests: + - 1.2.2 [\#3482](https://github.com/openwallet-foundation/acapy/pull/3482) [swcurran](https://github.com/swcurran) + ## 1.2.1 ### January 21, 2025 @@ -16,7 +196,7 @@ The same **[deprecation notices](#101-deprecation-notices)** from the [1.1.0](#1 There are no breaking changes in this release, just fixes, new tests and minor updates. -#### 1.2.1 Categorized List of Pull Requests +### 1.2.1 Categorized List of Pull Requests - Linked Data Proof and Key Type Additions - Support EcdsaSecp256r1Signature2019 linked data proof [\#3443](https://github.com/openwallet-foundation/acapy/pull/3443) [gmulhearn](https://github.com/gmulhearn) @@ -86,7 +266,7 @@ A fix for a multi-tenancy bug in the holding of VC-LD credentials that resulted [PR #3391]: https://github.com/openwallet-foundation/acapy/pull/3391 -#### 1.2.0 Categorized List of Pull Requests +### 1.2.0 Categorized List of Pull Requests - AnonCreds VC Issuance and Presentation Enhancement / Fixes - Fix indy fallback format in presentation from holder [\#3413](https://github.com/openwallet-foundation/acapy/pull/3413) [jamshale](https://github.com/jamshale) @@ -140,7 +320,7 @@ A fix for a multi-tenancy bug in the holding of VC-LD credentials that resulted - The latest tag doesn't exist in git, just github [\#3392](https://github.com/openwallet-foundation/acapy/pull/3392) [ryjones](https://github.com/ryjones) - :art: Fix model name for consistency [\#3382](https://github.com/openwallet-foundation/acapy/pull/3382) [ff137](https://github.com/ff137) - Fix for demo initial cred_type override [\#3378](https://github.com/openwallet-foundation/acapy/pull/3378) [ianco](https://github.com/ianco) - - :zap: Add class caching to DeferLoad [\#3361](https://github.com/openwallet-foundation/acapy/pull/3361) [ff137](https://github.com/ff137 + - :zap: Add class caching to DeferLoad [\#3361](https://github.com/openwallet-foundation/acapy/pull/3361) [ff137](https://github.com/ff137) - :art: Sync Ruff version in configs and apply formatting [\#3358](https://github.com/openwallet-foundation/acapy/pull/3358) [ff137](https://github.com/ff137) - :art: Replace deprecated ABC decorators [\#3357](https://github.com/openwallet-foundation/acapy/pull/3357) [ff137](https://github.com/ff137) - :art: Refactor the logging module monolith [\#3319](https://github.com/openwallet-foundation/acapy/pull/3319) [ff137](https://github.com/ff137) @@ -150,7 +330,7 @@ A fix for a multi-tenancy bug in the holding of VC-LD credentials that resulted - Remove in memory wallet [\#3311](https://github.com/openwallet-foundation/acapy/pull/3311) [jamshale](https://github.com/jamshale) - Consolidate Dependabot updates and other library/dependency updates - - Week 49 Library upgrades [\#3368](https://github.com/openwallet-foundation/acapy/pull/3368) [jamshale](https://github.com/jamshale) + - Week 49 Library upgrades [\#3368](https://github.com/openwallet-foundation/acapy/pull/3368) [jamshale](https://github.com/jamshale) - :arrow_up: Update lock file [\#3296](https://github.com/openwallet-foundation/acapy/pull/3296) [ff137](https://github.com/ff137) - Release management pull requests: @@ -165,38 +345,16 @@ A fix for a multi-tenancy bug in the holding of VC-LD credentials that resulted ACA-Py Release 1.1.1 was a release candidate for 1.2.0. A mistake in the release PR meant the 1.1.1rc0 was tagged published to PyPi as Release 1.1.1. Since that was not intended to be a final release, the release changelog for 1.2.0 includes the Pull Requests that would have been in 1.1.1. -## 0.12.3 - -### December 17, 2024 - -A patch release to add address a bug found in the Linked Data Verifiable Credential handling for multi-tenant holders. The bug was fixed in the main branch, [PR 3391 - BREAKING: VCHolder multitenant binding](https://github.com/openwallet-foundation/acapy/pull/3391), and with this release is backported to 0.12 Long Term Support branch. Prior to this release, holder credentials received into a tenant wallet were actually received into the multi-tenant admin wallet. - -### 0.12.3 Breaking Changes - -There are no breaking changes in this release. - -#### 0.12.3 Categorized List of Pull Requests - -- Multitenant LD-VC Holders - - Patch PR 3391 - 0.12.lts [\#3396](https://github.com/openwallet-foundation/acapy/pull/3396) -- Release management pull requests - - 0.12.3 [\#3408](https://github.com/hyperledger/aries-cloudagent-python/pull/3408) [swcurran](https://github.com/swcurran) - - 0.12.3rc0 [\#3406](https://github.com/hyperledger/aries-cloudagent-python/pull/3406) [swcurran](https://github.com/swcurran) - ## 1.1.0 ### October 15, 2024 Release 1.1.0 is the first release of ACA-Py from the [OpenWallet Foundation] (OWF). The only reason for the release is to test out all of the release publishing actions now that we have moved the repo to its new home ([https://github.com/openwallet-foundation/acapy](https://github.com/openwallet-foundation/acapy)). Almost all of the changes in the release are related to the move. -[OpenWallet Foundation]: https://openwallet.foundation/ - -The move triggered some big changes for those with existing ACA-Py deployments resulting from the change in the GitHub organization (from Hyperledger to OWF) and source code name (from `aries_cloudagent` to `acapy_agent`). See the [Release 1.1.0 breaking changes](#110rc0-breaking-changes) for the details. +The move triggered some big changes for those with existing ACA-Py deployments resulting from the change in the GitHub organization (from Hyperledger to OWF) and source code name (from `aries_cloudagent` to `acapy_agent`). See the [Release 1.1.0 breaking changes](#110-breaking-changes) for the details. For up to date details on what the repo move means for ACA-Py users, including steps for updating deployments, please follow the updates in [GitHub Issue #3250]. We'll keep you informed about the approach, timeline, and progress of the move. Stay tuned! -[GitHub Issue #3250]: https://github.com/hyperledger/aries-cloudagent-python/issues/3250 - ### 1.1.0 Deprecation Notices The same **[deprecation notices](#101-deprecation-notices)** from the [1.0.1](#101) release about AIP 1.0 protocols still apply. The protocols remain in the 1.1.0 release, but will be moved out of the core and into plugins soon. Please review these notifications carefully! @@ -210,7 +368,6 @@ The only (but significant) breaking changes in 1.1.0 are related to the GitHub o - the use of the OWF organizational GitHub Container Registry ([GHCR]) and `acapy_agent` as the name for release container image artifacts. - The patterns for the image tags remain the same as before. So, for example, the new nightly artifact can be found here: `docker pull ghcr.io/openwallet-foundation/acapy-agent:py3.12-nightly`. -[PyPi]: https://pypi.org [GHCR]: https://ghcr.io Anyone deploying ACA-Py should use this release to update their existing deployments. Since there are no other changes to ACA-Py, any issues found should relate back to those changes. @@ -267,15 +424,6 @@ In an attempt to shorten the categorized list of PRs in the release, rather than - In the next ACA-Py release, we will be dropping from the core ACA-Py repository the AIP 1.0 [RFC 0160 Connections], [RFC 0037 Issue Credentials v1.0] and [RFC 0037 Present Proof v1.0] DIDComm protocols. Each of the protocols will be moved to the [ACA-Py Plugins] repo. All deployers that use those protocols **SHOULD** update to the [AIP 2.0] versions of those protocols ([RFC 0434 Out of Band]+[RFC 0023 DID Exchange], [RFC 0453 Issue Credential v2.0] and [RFC 0454 Present Proof v2.0], respectively). Once the protocols are removed from ACA-Py, anyone still using those protocols **MUST** adjust their configuration to load those protocols from the respective plugins. -[RFC 0160 Connections]: https://hyperledger.github.io/aries-rfcs/latest/features/0160-connection-protocol/ -[RFC 0037 Issue Credentials]: https://hyperledger.github.io/aries-rfcs/latest/features/0036-issue-credential/ -[RFC 0037 Present Proof]: https://hyperledger.github.io/aries-rfcs/latest/features/0037-present-proof/ -[AIP 2.0]: https://hyperledger.github.io/aries-rfcs/latest/aip2/0003-protocols/ -[RFC 0434 Out of Band]: https://hyperledger.github.io/aries-rfcs/latest/aip2/0434-outofband/ -[RFC 0023 DID Exchange]: https://hyperledger.github.io/aries-rfcs/latest/aip2/0023-did-exchange/ -[RFC 0453 Issue Credential v2.0]: https://hyperledger.github.io/aries-rfcs/latest/aip2/0453-issue-credential-v2/ -[RFC 0454 Present Proof v2.0]: https://hyperledger.github.io/aries-rfcs/latest/aip2/0454-present-proof-v2/ - ### 1.0.1 Breaking Changes There are no breaking changes in ACA-Py Release 1.0.1. @@ -521,6 +669,84 @@ With the focus of the pull requests for this release on stabilizing the implemen - chore(deps): Bump untergeek/curator from 8.0.2 to 8.0.15 in /demo/elk-stack/extensions/curator [\#2969](https://github.com/hyperledger/aries-cloudagent-python/pull/2969) [dependabot bot](https://github.com/dependabot bot) - chore(deps): Bump ecdsa from 0.16.1 to 0.19.0 in the pip group across 1 directory [\#2933](https://github.com/hyperledger/aries-cloudagent-python/pull/2933) [dependabot bot](https://github.com/dependabot bot) +## 0.12.6 + +### March 13, 2025 + +This patch release addresses a bug in the handling connection reuse in multitenancy environments. This is a backport of the PR [fix: connection reuse with multi-tenancy #3543](https://github.com/openwallet-foundation/acapy/pull/3543). This fixes the issue when using multi-tenancy, calls to `POST /out-of-band/receive-invitation?use_existing_connection=true` failing with a record not found error, despite connection reuse actually being completed in the background. + +### 0.12.6 Breaking Changes + +There are no breaking changes in this release. + +#### 0.12.6 Categorized List of Pull Requests + +- Multitenancy Fixes + - fix: cherry-pick fixes from main to 0.12.lts [\#3578](https://github.com/openwallet-foundation/acapy/pull/3578) [thiagoromanos](https://github.com/thiagoromanos) + +- Release management pull requests: + - 0.12.6 [\#3583](https://github.com/openwallet-foundation/acapy/pull/3583) [swcurran](https://github.com/swcurran) + +## 0.12.5 + +### March 6, 2025 + +This patch release addresses a bug in the publishing of AnonCreds revocation entries that caused the ledger and issuer wallet to become out of sync. As a result, revoked credentials were not being correctly flagged as revoked when presented. Previously, this issue was mitigated by an automatic “sync-revocation” process, which generally resolved the problem. However, we recently identified scenarios where the presence of an Indy Endorser in the revocation publication flow caused the “sync-revocation” process to fail silently. + +This patch resolves that issue. Once applied, if a revocation batch results in an out-of-sync state, the “sync-revocation” process will automatically run to correct it. + +For more details, see [Issue 3546](https://github.com/openwallet-foundation/acapy/issues/3546). + +### 0.12.5 Breaking Changes + +There are no breaking changes in this release. + +#### 0.12.5 Categorized List of Pull Requests + +- AnonCreds Revocation Fixes + - 0.12.lts Patch the fix_ledger_entry improvements [\#3558](https://github.com/openwallet-foundation/acapy/pull/3558) [jamshale](https://github.com/jamshale) + - 0.12.lts Fix revocation accum sync when endorsement txn fails (#3547) [\#3554](https://github.com/openwallet-foundation/acapy/pull/3554) [jamshale](https://github.com/jamshale) + +- Release management pull requests: + - 0.12.5 [\#3560](https://github.com/openwallet-foundation/acapy/pull/3560) [swcurran](https://github.com/swcurran) + +## 0.12.4 + +### January 30, 2025 + +A patch release to upgrade [Askar](https://github.com/openwallet-foundation/askar) to [0.4.3](https://github.com/openwallet-foundation/askar/releases/tag/v0.4.3) and fixes a problem with wallet names in a multitenant, single-wallet configuration. + +Addresses the problem outlined in [#3471](https://github.com/openwallet-foundation/acapy/issues/3471) around profiles in multi-tenant/single wallet deployments. The update to Askar addresses an intermittent hang on startup, and a dependency change that can result in a substantial performance improvement in some cases. See issues: [openwallet-foundation/askar#350](https://github.com/openwallet-foundation/askar/pull/350), [openwallet-foundation/askar#351](https://github.com/openwallet-foundation/askar/pull/351), [openwallet-foundation/askar#354](https://github.com/openwallet-foundation/askar/pull/354). This [comment on one of the PRs](https://github.com/openwallet-foundation/askar/pull/350#issuecomment-2615727109) describes the scenario where a substantial performance improvement was seen as a result of the change in Askar. + +### 0.12.4 Breaking Changes + +There are no breaking changes in this release. + +#### 0.12.4 Categorized List of Pull Requests + +- Multitenant Single Wallet Configurations + - 0.12 LTS: Askar upgrade and fix profile unique names [\#3475](https://github.com/openwallet-foundation/acapy/pull/3475) +- Release management pull requests + - 0.12.4 [\#3481](https://github.com/hyperledger/aries-cloudagent-python/pull/3481) [swcurran](https://github.com/swcurran) + +## 0.12.3 + +### December 17, 2024 + +A patch release to add address a bug found in the Linked Data Verifiable Credential handling for multi-tenant holders. The bug was fixed in the main branch, [PR 3391 - BREAKING: VCHolder multitenant binding](https://github.com/openwallet-foundation/acapy/pull/3391), and with this release is backported to 0.12 Long Term Support branch. Prior to this release, holder credentials received into a tenant wallet were actually received into the multi-tenant admin wallet. + +### 0.12.3 Breaking Changes + +There are no breaking changes in this release. + +#### 0.12.3 Categorized List of Pull Requests + +- Multitenant LD-VC Holders + - Patch PR 3391 - 0.12.lts [\#3396](https://github.com/openwallet-foundation/acapy/pull/3396) +- Release management pull requests + - 0.12.3 [\#3408](https://github.com/hyperledger/aries-cloudagent-python/pull/3408) [swcurran](https://github.com/swcurran) + - 0.12.3rc0 [\#3406](https://github.com/hyperledger/aries-cloudagent-python/pull/3406) [swcurran](https://github.com/swcurran) + ## 0.12.2 ### August 2, 2024 @@ -809,7 +1035,7 @@ New deprecation notices were added to ACA-Py on startup and in the OpenAPI/Swagg A patch release to add a fix that ensures that sufficient webhook information is sent to an ACA-Py controller that is executing the [AIP 2.0 Present Proof 2.0 Protocol]. -[AIP 2.0 Present Proof 2.0 Protocol]: https://hyperledger.github.io/aries-rfcs/latest/aip2/0454-present-proof-v2/ +[AIP 2.0 Present Proof 2.0 Protocol]: https://identity.foundation/aries-rfcs/latest/aip2/0454-present-proof-v2/ ### 0.11.3 Breaking Changes diff --git a/Managing-ACA-Py-Doc-Site.md b/Managing-ACA-Py-Doc-Site.md index e4abbcf478..ba5c9ebcab 100644 --- a/Managing-ACA-Py-Doc-Site.md +++ b/Managing-ACA-Py-Doc-Site.md @@ -20,7 +20,7 @@ and mkdocs configuration. When the GitHub Action fires, it runs a container that carries out the following steps: -- Checks out the triggering branch, either `main` or `docs-v` (e.g `docs-v1.2.1`). +- Checks out the triggering branch, either `main` or `docs-v` (e.g `docs-v1.3.0`). - Runs the script [scripts/prepmkdocs.sh], which moves and updates some of the markdown files so that they fit into the generated site. See the comments in the scripts for details about the copying and editing done via the script. In @@ -97,7 +97,7 @@ To delete the documentation version, do the following: - Check your `git status` and make sure there are no changes in the branch -- e.g., new files that shouldn't be added to the `gh-pages` branch. If there are any -- delete the files so they are not added. -- Remove the folder for the RC. For example `rm -rf 1.2.1rc0` +- Remove the folder for the RC. For example `rm -rf 1.3.0rc0` - Edit the `versions.json` file and remove the reference to the RC release in the file. - Push the changes via a PR to the ACA-Py `gh-pages` branch (don't PR them into diff --git a/PUBLISHING.md b/PUBLISHING.md index 89a213299c..26dd39f773 100644 --- a/PUBLISHING.md +++ b/PUBLISHING.md @@ -6,7 +6,7 @@ a major, minor or patch release, per [semver](https://semver.org/) rules. Once ready to do a release, create a local branch that includes the following updates: -1. Create a local PR branch from an updated `main` branch, e.g. "1.2.1". +1. Create a local PR branch from an updated `main` branch, e.g. "1.3.0rc0". 2. See if there are any Document Site `mkdocs` changes needed. Run the script `./scripts/prepmkdocs.sh; mkdocs`. Watch the log, noting particularly if @@ -140,7 +140,7 @@ Once you have the list of PRs: [publish-indy.yml]: https://github.com/openwallet-foundation/acapy/blob/main/.github/workflows/publish-indy.yml 12. When a new release is tagged, create a new branch at the same commit with - the branch name in the format `docs-v`, for example, `docs-v1.2.1`. + the branch name in the format `docs-v`, for example, `docs-v1.3.0rc0`. The creation of the branch triggers the execution of the [publish-docs] GitHub Action which generates the documentation for the new release, publishing it at [https://aca-py.org]. The GitHub Action also executes when diff --git a/README.md b/README.md index 9924a2de3b..2ed768e9d1 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ the [LTS strategy](./LTS-Strategy.md). Current LTS releases: -- Release [1.2](https://github.com/openwallet-foundation/acapy/releases/tag/1.2.1) **Current LTS Release** -- Release [0.12](https://github.com/openwallet-foundation/acapy/releases/tag/0.12.3) **End of Life: October 2025** +- Release [1.2](https://github.com/openwallet-foundation/acapy/releases/tag/1.2.4) **Current LTS Release** +- Release [0.12](https://github.com/openwallet-foundation/acapy/releases/tag/0.12.6) **End of Life: October 2025** Past LTS releases: diff --git a/docs/conf.py b/docs/conf.py index 48b79fdc62..8b998d1d3f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -60,6 +60,8 @@ "unflatten", "yaml", "uuid_utils", + "did_webvh", + "canonicaljson", ] # "acapy_agent.tests.test_conductor", @@ -72,7 +74,7 @@ # -- Project information ----------------------------------------------------- project = "ACA-Py" -copyright = "2024, Province of British Columbia" +copyright = "2025, Province of British Columbia" author = "Province of British Columbia" # The short X.Y version @@ -226,7 +228,6 @@ "ACA-Py", "ACA-Py Documentation", author, - "ACA-Py", "A Decentralized Trust Agent implemented in Python and\ suitable for use in (almost) any non-mobile environment.", "Miscellaneous", diff --git a/docs/features/SupportedRFCs.md b/docs/features/SupportedRFCs.md index 52358ee80c..ba9b69e263 100644 --- a/docs/features/SupportedRFCs.md +++ b/docs/features/SupportedRFCs.md @@ -8,7 +8,7 @@ ACA-Py or the repository `main` branch. Reminders (and PRs!) to update this page welcome! If you have any questions, please contact us on the #aries channel on [OpenWallet Foundation Discord](https://discord.gg/openwallet-foundation) or through an issue in this repo. -**Last Update**: 2025-01-21, Release 1.2.1 +**Last Update**: 2025-03-20, Release 1.3.0rc0 > The checklist version of this document was created as a joint effort > between [Northern Block](https://northernblock.io/), [Animo Solutions](https://animo.id/) and the Ontario government, on behalf of the Ontario government. @@ -21,7 +21,7 @@ ACA-Py and other decentralized trust Frameworks and Agents. | AIP Version | Supported | Notes | | - | :-------: | -------- | -| AIP 1.0 | :white_check_mark: | Fully supported. Deprecation notices published| +| AIP 1.0 | :white_check_mark: | Partially supported. Deprecation notices published, Connections protocol moved into an [ACA-Py Plugin](https://plugins.aca-py.org/latest/connections/)| | AIP 2.0 | :white_check_mark: | Fully supported. | A summary of the Aries Interop Profiles and Aries RFCs supported in ACA-Py can be found [later in this document](#supported-rfcs). @@ -112,8 +112,8 @@ A summary of the Aries Interop Profiles and Aries RFCs supported in ACA-Py can b ### AIP 1.0 -All RFCs listed in [AIP -1.0](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0302-aries-interop-profile#aries-interop-profile-version-10) +Most RFCs listed in [AIP +1.0](https://identity.foundation/aries-rfcs/latest/concepts/0302-aries-interop-profile/#aries-interop-profile-version-10) are fully supported in ACA-Py, but deprecation and removal of some of the protocols has begun. The following table provides notes about the implementation of specific RFCs. @@ -121,13 +121,13 @@ of specific RFCs. | RFC | Supported | Notes | | --- | :--: | -- | | [0025-didcomm-transports](https://github.com/hyperledger/aries-rfcs/tree/b490ebe492985e1be9804fc0763119238b2e51ab/features/0025-didcomm-transports) | :white_check_mark: | ACA-Py currently supports HTTP and WebSockets for both inbound and outbound messaging. Transports are pluggable and an agent instance can use multiple inbound and outbound transports.| -| [0160-connection-protocol](https://github.com/hyperledger/aries-rfcs/tree/9b0aaa39df7e8bd434126c4b33c097aae78d65bf/features/0160-connection-protocol) | :white_check_mark: | **DEPRECATED** In the next release, the protocol will be removed. The protocol will continue to be available as an [ACA-Py plugin], but those upgrading to that pending release and continuing to use this protocol will need to include the plugin in their deployment configuration. Users **SHOULD** upgrade to the equivalent [AIP 2.0] protocols as soon as possible. | +| [0160-connection-protocol](https://github.com/hyperledger/aries-rfcs/tree/9b0aaa39df7e8bd434126c4b33c097aae78d65bf/features/0160-connection-protocol) | :x: | **MOVED TO PLUGIN** The protocol has been moved into the [ACA-Py plugin] repository. Those upgrading to Release 1.3.0 or later and continuing to use this protocol **MUST** include the [Connections plugin](https://plugins.aca-py.org/latest/connections/) in their deployment configuration. Users **SHOULD** upgrade to the equivalent [AIP 2.0] protocols as soon as possible. | | [0036-issue-credential-v1.0](https://github.com/hyperledger/aries-rfcs/tree/bb42a6c35e0d5543718fb36dd099551ab192f7b0/features/0036-issue-credential) | :white_check_mark: | **DEPRECATED** In the next release, the protocol will be removed. The protocol will continue to be available as an [ACA-Py plugin], but those upgrading to that pending release and continuing to use this protocol will need to include the plugin in their deployment configuration. Users **SHOULD** upgrade to the equivalent [AIP 2.0] protocols as soon as possible. | | [0037-present-proof-v1.0](https://github.com/hyperledger/aries-rfcs/tree/4fae574c03f9f1013db30bf2c0c676b1122f7149/features/0037-present-proof) | :white_check_mark: | **DEPRECATED** In the next release, the protocol will be removed. It will continue to be available as an [ACA-Py plugin], but those upgrading to that pending release and continuing to use this protocol will need to include the plugin in their deployment configuration. Users **SHOULD** upgrade to the equivalent [AIP 2.0] protocols as soon as possible. | [ACA-Py plugin]: https://plugins.aca-py.org -[AIP 2.0]: https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0302-aries-interop-profile#aries-interop-profile-version-20 +[AIP 2.0]: https://identity.foundation/aries-rfcs/latest/concepts/0302-aries-interop-profile/#aries-interop-profile-version-20 ### AIP 2.0 diff --git a/docs/index.rst b/docs/index.rst index 4f62157cef..e950aa2b21 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -29,7 +29,7 @@ drill into the modules, subpackages and submodules that make up ACA-Py. Developers that are interested in what DIDComm protocols are supported in ACA-Py should take a look at the `protocols `_ package. These should align with the corresponding -`aries-rfcs protocols `_. +`aries-rfcs protocols `_. Decorators defined in aries-rfcs and implemented in ACA-Py can be found `here `_. Some general purpose subpackages that might be of interest include diff --git a/open-api/openapi.json b/open-api/openapi.json index bb10b0ea7d..7f0e57e9a0 100644 --- a/open-api/openapi.json +++ b/open-api/openapi.json @@ -2,7 +2,7 @@ "openapi" : "3.0.1", "info" : { "title" : "Aries Cloud Agent", - "version" : "v1.2.1" + "version" : "v1.3.0rc0" }, "servers" : [ { "url" : "/" @@ -50,10 +50,6 @@ "name" : "basicmessage" }, { "description" : "Connection management", - "externalDocs" : { - "description" : "Specification", - "url" : "https://github.com/hyperledger/aries-rfcs/tree/9b0aaa39df7e8bd434126c4b33c097aae78d65bf/features/0160-connection-protocol" - }, "name" : "connection" }, { "description" : "Credential definition operations", @@ -69,6 +65,13 @@ "url" : "https://w3c.github.io/vc-data-model/#credentials" }, "name" : "credentials" + }, { + "description" : "Endpoints for managing dids", + "externalDocs" : { + "description" : "Specification", + "url" : "https://www.w3.org/TR/did-core/" + }, + "name" : "did" }, { "description" : "Connection management via DID exchange", "externalDocs" : { @@ -477,7 +480,7 @@ "name" : "rev_reg_id", "required" : true, "schema" : { - "pattern" : "^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}):4:([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}):3:CL:(([1-9][0-9]*)|([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}:2:.+:[0-9.]+))(:.+)?:CL_ACCUM:(.+$)", + "pattern" : "^(.+$)", "type" : "string" } } ], @@ -486,7 +489,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/RevocationModuleResponse" + "$ref" : "#/components/schemas/AnoncredsRevocationModuleResponse" } } }, @@ -505,7 +508,7 @@ "name" : "rev_reg_id", "required" : true, "schema" : { - "pattern" : "^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}):4:([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}):3:CL:(([1-9][0-9]*)|([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}:2:.+:[0-9.]+))(:.+)?:CL_ACCUM:(.+$)", + "pattern" : "^(.+$)", "type" : "string" } } ], @@ -514,7 +517,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/RevocationModuleResponse" + "$ref" : "#/components/schemas/AnoncredsRevocationModuleResponse" } } }, @@ -948,7 +951,7 @@ "content" : { "application/octet-stream" : { "schema" : { - "$ref" : "#/components/schemas/RevocationAnoncredsModuleResponse" + "$ref" : "#/components/schemas/AnoncredsRevocationModuleResponse" } } }, @@ -976,7 +979,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/RevocationAnoncredsModuleResponse" + "$ref" : "#/components/schemas/AnoncredsRevocationModuleResponse" } } }, @@ -1125,9 +1128,17 @@ "in" : "query", "name" : "connection_protocol", "schema" : { - "enum" : [ "connections/1.0", "didexchange/1.0", "didexchange/1.1" ], + "enum" : [ "didexchange/1.0", "didexchange/1.1" ], "type" : "string" } + }, { + "description" : "Order results in descending order if true", + "in" : "query", + "name" : "descending", + "schema" : { + "default" : false, + "type" : "boolean" + } }, { "description" : "invitation key", "in" : "query", @@ -1149,6 +1160,8 @@ "name" : "limit", "schema" : { "default" : 100, + "maximum" : 10000, + "minimum" : 1, "type" : "integer" } }, { @@ -1156,7 +1169,7 @@ "in" : "query", "name" : "my_did", "schema" : { - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", "type" : "string" } }, { @@ -1165,8 +1178,18 @@ "name" : "offset", "schema" : { "default" : 0, + "minimum" : 0, "type" : "integer" } + }, { + "description" : "The column to order results by. Only \"id\" is currently supported.", + "in" : "query", + "name" : "order_by", + "schema" : { + "default" : "id", + "enum" : [ "id" ], + "type" : "string" + } }, { "description" : "Connection state", "in" : "query", @@ -1180,7 +1203,7 @@ "in" : "query", "name" : "their_did", "schema" : { - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", "type" : "string" } }, { @@ -1188,7 +1211,7 @@ "in" : "query", "name" : "their_public_did", "schema" : { - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", "type" : "string" } }, { @@ -1216,65 +1239,6 @@ "tags" : [ "connection" ] } }, - "/connections/create-invitation" : { - "post" : { - "deprecated" : true, - "parameters" : [ { - "description" : "Alias", - "in" : "query", - "name" : "alias", - "schema" : { - "type" : "string" - } - }, { - "description" : "Auto-accept connection (defaults to configuration)", - "in" : "query", - "name" : "auto_accept", - "schema" : { - "type" : "boolean" - } - }, { - "description" : "Create invitation for multiple use (default false)", - "in" : "query", - "name" : "multi_use", - "schema" : { - "type" : "boolean" - } - }, { - "description" : "Create invitation from public DID (default false)", - "in" : "query", - "name" : "public", - "schema" : { - "type" : "boolean" - } - } ], - "requestBody" : { - "content" : { - "*/*" : { - "schema" : { - "$ref" : "#/components/schemas/CreateInvitationRequest" - } - } - }, - "required" : false - }, - "responses" : { - "200" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/InvitationResult" - } - } - }, - "description" : "" - } - }, - "summary" : "Create a new connection invitation", - "tags" : [ "connection" ], - "x-codegen-request-body-name" : "body" - } - }, "/connections/create-static" : { "post" : { "requestBody" : { @@ -1304,59 +1268,6 @@ "x-codegen-request-body-name" : "body" } }, - "/connections/receive-invitation" : { - "post" : { - "deprecated" : true, - "parameters" : [ { - "description" : "Alias", - "in" : "query", - "name" : "alias", - "schema" : { - "type" : "string" - } - }, { - "description" : "Auto-accept connection (defaults to configuration)", - "in" : "query", - "name" : "auto_accept", - "schema" : { - "type" : "boolean" - } - }, { - "description" : "Identifier for active mediation record to be used", - "in" : "query", - "name" : "mediation_id", - "schema" : { - "pattern" : "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", - "type" : "string" - } - } ], - "requestBody" : { - "content" : { - "*/*" : { - "schema" : { - "$ref" : "#/components/schemas/ReceiveInvitationRequest" - } - } - }, - "required" : false - }, - "responses" : { - "200" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ConnRecord" - } - } - }, - "description" : "" - } - }, - "summary" : "Receive a new connection invitation", - "tags" : [ "connection" ], - "x-codegen-request-body-name" : "body" - } - }, "/connections/{conn_id}" : { "delete" : { "parameters" : [ { @@ -1409,93 +1320,6 @@ "tags" : [ "connection" ] } }, - "/connections/{conn_id}/accept-invitation" : { - "post" : { - "deprecated" : true, - "parameters" : [ { - "description" : "Connection identifier", - "in" : "path", - "name" : "conn_id", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "description" : "Identifier for active mediation record to be used", - "in" : "query", - "name" : "mediation_id", - "schema" : { - "pattern" : "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", - "type" : "string" - } - }, { - "description" : "My URL endpoint", - "in" : "query", - "name" : "my_endpoint", - "schema" : { - "pattern" : "^[A-Za-z0-9\\.\\-\\+]+://([A-Za-z0-9][.A-Za-z0-9-_]+[A-Za-z0-9])+(:[1-9][0-9]*)?(/[^?&#]+)?$", - "type" : "string" - } - }, { - "description" : "Label for connection", - "in" : "query", - "name" : "my_label", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "200" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ConnRecord" - } - } - }, - "description" : "" - } - }, - "summary" : "Accept a stored connection invitation", - "tags" : [ "connection" ] - } - }, - "/connections/{conn_id}/accept-request" : { - "post" : { - "deprecated" : true, - "parameters" : [ { - "description" : "Connection identifier", - "in" : "path", - "name" : "conn_id", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "description" : "My URL endpoint", - "in" : "query", - "name" : "my_endpoint", - "schema" : { - "pattern" : "^[A-Za-z0-9\\.\\-\\+]+://([A-Za-z0-9][.A-Za-z0-9-_]+[A-Za-z0-9])+(:[1-9][0-9]*)?(/[^?&#]+)?$", - "type" : "string" - } - } ], - "responses" : { - "200" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ConnRecord" - } - } - }, - "description" : "" - } - }, - "summary" : "Accept a stored connection request", - "tags" : [ "connection" ] - } - }, "/connections/{conn_id}/endpoints" : { "get" : { "parameters" : [ { @@ -1770,7 +1594,7 @@ "in" : "query", "name" : "issuer_did", "schema" : { - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" } }, { @@ -1786,7 +1610,7 @@ "in" : "query", "name" : "schema_issuer_did", "schema" : { - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" } }, { @@ -2067,6 +1891,8 @@ "in" : "query", "name" : "limit", "schema" : { + "maximum" : 10000, + "minimum" : 1, "type" : "integer" } }, { @@ -2074,6 +1900,7 @@ "in" : "query", "name" : "offset", "schema" : { + "minimum" : 0, "type" : "integer" } }, { @@ -2204,6 +2031,35 @@ "x-codegen-request-body-name" : "body" } }, + "/did/indy/create" : { + "post" : { + "requestBody" : { + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/CreateRequest" + } + } + }, + "required" : false + }, + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/CreateResponse" + } + } + }, + "description" : "" + } + }, + "summary" : "Create a did:indy", + "tags" : [ "did" ], + "x-codegen-request-body-name" : "body" + } + }, "/didexchange/create-request" : { "post" : { "parameters" : [ { @@ -2212,7 +2068,7 @@ "name" : "their_public_did", "required" : true, "schema" : { - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", "type" : "string" } }, { @@ -2718,12 +2574,22 @@ "schema" : { "type" : "string" } + }, { + "description" : "Order results in descending order if true", + "in" : "query", + "name" : "descending", + "schema" : { + "default" : false, + "type" : "boolean" + } }, { "description" : "Number of results to return", "in" : "query", "name" : "limit", "schema" : { "default" : 100, + "maximum" : 10000, + "minimum" : 1, "type" : "integer" } }, { @@ -2732,8 +2598,18 @@ "name" : "offset", "schema" : { "default" : 0, + "minimum" : 0, "type" : "integer" } + }, { + "description" : "The column to order results by. Only \"id\" is currently supported.", + "in" : "query", + "name" : "order_by", + "schema" : { + "default" : "id", + "enum" : [ "id" ], + "type" : "string" + } }, { "description" : "Role assigned in credential exchange", "in" : "query", @@ -3209,12 +3085,22 @@ "schema" : { "type" : "string" } + }, { + "description" : "Order results in descending order if true", + "in" : "query", + "name" : "descending", + "schema" : { + "default" : false, + "type" : "boolean" + } }, { "description" : "Number of results to return", "in" : "query", "name" : "limit", "schema" : { "default" : 100, + "maximum" : 10000, + "minimum" : 1, "type" : "integer" } }, { @@ -3223,8 +3109,18 @@ "name" : "offset", "schema" : { "default" : 0, + "minimum" : 0, "type" : "integer" } + }, { + "description" : "The column to order results by. Only \"id\" is currently supported.", + "in" : "query", + "name" : "order_by", + "schema" : { + "default" : "id", + "enum" : [ "id" ], + "type" : "string" + } }, { "description" : "Role assigned in credential exchange", "in" : "query", @@ -3697,7 +3593,7 @@ "name" : "did", "required" : true, "schema" : { - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" } }, { @@ -3733,7 +3629,7 @@ "name" : "did", "required" : true, "schema" : { - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" } } ], @@ -3761,7 +3657,7 @@ "name" : "did", "required" : true, "schema" : { - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" } } ], @@ -3825,7 +3721,7 @@ "name" : "did", "required" : true, "schema" : { - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" } }, { @@ -4559,11 +4455,21 @@ "/multitenancy/wallets" : { "get" : { "parameters" : [ { + "description" : "Order results in descending order if true", + "in" : "query", + "name" : "descending", + "schema" : { + "default" : false, + "type" : "boolean" + } + }, { "description" : "Number of results to return", "in" : "query", "name" : "limit", "schema" : { "default" : 100, + "maximum" : 10000, + "minimum" : 1, "type" : "integer" } }, { @@ -4572,8 +4478,18 @@ "name" : "offset", "schema" : { "default" : 0, + "minimum" : 0, "type" : "integer" } + }, { + "description" : "The column to order results by. Only \"id\" is currently supported.", + "in" : "query", + "name" : "order_by", + "schema" : { + "default" : "id", + "enum" : [ "id" ], + "type" : "string" + } }, { "description" : "Wallet name", "in" : "query", @@ -4792,12 +4708,22 @@ "schema" : { "type" : "string" } + }, { + "description" : "Order results in descending order if true", + "in" : "query", + "name" : "descending", + "schema" : { + "default" : false, + "type" : "boolean" + } }, { "description" : "Number of results to return", "in" : "query", "name" : "limit", "schema" : { "default" : 100, + "maximum" : 10000, + "minimum" : 1, "type" : "integer" } }, { @@ -4806,8 +4732,18 @@ "name" : "offset", "schema" : { "default" : 0, + "minimum" : 0, "type" : "integer" } + }, { + "description" : "The column to order results by. Only \"id\" is currently supported.", + "in" : "query", + "name" : "order_by", + "schema" : { + "default" : "id", + "enum" : [ "id" ], + "type" : "string" + } }, { "description" : "Role assigned in presentation exchange", "in" : "query", @@ -4935,6 +4871,8 @@ "in" : "query", "name" : "limit", "schema" : { + "maximum" : 10000, + "minimum" : 1, "type" : "integer" } }, { @@ -4942,6 +4880,7 @@ "in" : "query", "name" : "offset", "schema" : { + "minimum" : 0, "type" : "integer" } }, { @@ -5223,12 +5162,22 @@ "schema" : { "type" : "string" } + }, { + "description" : "Order results in descending order if true", + "in" : "query", + "name" : "descending", + "schema" : { + "default" : false, + "type" : "boolean" + } }, { "description" : "Number of results to return", "in" : "query", "name" : "limit", "schema" : { "default" : 100, + "maximum" : 10000, + "minimum" : 1, "type" : "integer" } }, { @@ -5237,8 +5186,18 @@ "name" : "offset", "schema" : { "default" : 0, + "minimum" : 0, "type" : "integer" } + }, { + "description" : "The column to order results by. Only \"id\" is currently supported.", + "in" : "query", + "name" : "order_by", + "schema" : { + "default" : "id", + "enum" : [ "id" ], + "type" : "string" + } }, { "description" : "Role assigned in presentation exchange", "in" : "query", @@ -5369,6 +5328,8 @@ "in" : "query", "name" : "limit", "schema" : { + "maximum" : 10000, + "minimum" : 1, "type" : "integer" } }, { @@ -5376,6 +5337,7 @@ "in" : "query", "name" : "offset", "schema" : { + "minimum" : 0, "type" : "integer" } }, { @@ -6386,7 +6348,7 @@ "in" : "query", "name" : "schema_issuer_did", "schema" : { - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" } }, { @@ -7186,7 +7148,7 @@ "in" : "query", "name" : "did", "schema" : { - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", "type" : "string" } }, { @@ -7274,7 +7236,7 @@ "name" : "did", "required" : true, "schema" : { - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", "type" : "string" } } ], @@ -7318,7 +7280,7 @@ "name" : "did", "required" : true, "schema" : { - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", "type" : "string" } }, { @@ -7367,7 +7329,7 @@ "name" : "did", "required" : true, "schema" : { - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", "type" : "string" } } ], @@ -7667,10 +7629,12 @@ "AddProof" : { "properties" : { "document" : { + "additionalProperties" : { + "type" : "object" + }, "example" : { "hello" : "world" }, - "properties" : { }, "type" : "object" }, "options" : { @@ -7692,10 +7656,12 @@ "AddProofResponse" : { "properties" : { "secured_document" : { + "additionalProperties" : { + "type" : "object" + }, "example" : { "hello" : "world" }, - "properties" : { }, "type" : "object" } }, @@ -7705,8 +7671,10 @@ "AdminConfig" : { "properties" : { "config" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Configuration settings", - "properties" : { }, "type" : "object" } }, @@ -7738,8 +7706,10 @@ "AdminStatus" : { "properties" : { "conductor" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Conductor statistics", - "properties" : { }, "type" : "object" }, "label" : { @@ -7748,8 +7718,10 @@ "type" : "string" }, "timing" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Timing results", - "properties" : { }, "type" : "object" }, "version" : { @@ -7973,6 +7945,9 @@ }, "type" : "object" }, + "AnoncredsRevocationModuleResponse" : { + "type" : "object" + }, "AttachDecorator" : { "properties" : { "@id" : { @@ -8145,31 +8120,45 @@ "ClaimFormat" : { "properties" : { "di_vc" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "jwt" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "jwt_vc" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "jwt_vp" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "ldp" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "ldp_vc" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "ldp_vp" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" } }, @@ -8226,8 +8215,8 @@ }, "connection_protocol" : { "description" : "Connection protocol used", - "enum" : [ "connections/1.0", "didexchange/1.0", "didexchange/1.1" ], - "example" : "connections/1.0", + "enum" : [ "didexchange/1.0", "didexchange/1.1" ], + "example" : "didexchange/1.1", "type" : "string" }, "created_at" : { @@ -8266,7 +8255,7 @@ "my_did" : { "description" : "Our DID for connection", "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", "type" : "string" }, "request_id" : { @@ -8288,7 +8277,7 @@ "their_did" : { "description" : "Their DID for connection", "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", "type" : "string" }, "their_label" : { @@ -8317,64 +8306,6 @@ "required" : [ "connection_id" ], "type" : "object" }, - "ConnectionInvitation" : { - "properties" : { - "@id" : { - "description" : "Message identifier", - "example" : "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "type" : "string" - }, - "@type" : { - "description" : "Message type", - "example" : "https://didcomm.org/my-family/1.0/my-message-type", - "type" : "string" - }, - "did" : { - "description" : "DID for connection invitation", - "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", - "type" : "string" - }, - "imageUrl" : { - "description" : "Optional image URL for connection invitation", - "example" : "http://192.168.56.101/img/logo.jpg", - "format" : "url", - "nullable" : true, - "type" : "string" - }, - "label" : { - "description" : "Optional label for connection invitation", - "example" : "Bob", - "type" : "string" - }, - "recipientKeys" : { - "description" : "List of recipient keys", - "items" : { - "description" : "Recipient public key", - "example" : "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV", - "pattern" : "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{43,44}$", - "type" : "string" - }, - "type" : "array" - }, - "routingKeys" : { - "description" : "List of routing keys", - "items" : { - "description" : "Routing key", - "example" : "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV", - "pattern" : "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{43,44}$", - "type" : "string" - }, - "type" : "array" - }, - "serviceEndpoint" : { - "description" : "Service endpoint at which to reach this agent", - "example" : "http://192.168.56.101:8020", - "type" : "string" - } - }, - "type" : "object" - }, "ConnectionList" : { "properties" : { "results" : { @@ -8391,8 +8322,10 @@ "ConnectionMetadata" : { "properties" : { "results" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Dictionary of metadata associated with connection.", - "properties" : { }, "type" : "object" } }, @@ -8401,8 +8334,10 @@ "ConnectionMetadataSetRequest" : { "properties" : { "metadata" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Dictionary of metadata to set for connection.", - "properties" : { }, "type" : "object" } }, @@ -8420,8 +8355,8 @@ }, "my_did" : { "description" : "Local DID", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "my_seed" : { @@ -8430,8 +8365,8 @@ }, "their_did" : { "description" : "Remote DID", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "their_endpoint" : { @@ -8459,8 +8394,8 @@ "properties" : { "my_did" : { "description" : "Local DID", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "my_endpoint" : { @@ -8480,8 +8415,8 @@ }, "their_did" : { "description" : "Remote DID", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "their_verkey" : { @@ -8532,52 +8467,6 @@ }, "type" : "object" }, - "CreateInvitationRequest" : { - "properties" : { - "mediation_id" : { - "description" : "Identifier for active mediation record to be used", - "example" : "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "pattern" : "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", - "type" : "string" - }, - "metadata" : { - "description" : "Optional metadata to attach to the connection created with the invitation", - "properties" : { }, - "type" : "object" - }, - "my_label" : { - "description" : "Optional label for connection invitation", - "example" : "Bob", - "type" : "string" - }, - "recipient_keys" : { - "description" : "List of recipient keys", - "items" : { - "description" : "Recipient public key", - "example" : "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV", - "pattern" : "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{43,44}$", - "type" : "string" - }, - "type" : "array" - }, - "routing_keys" : { - "description" : "List of routing keys", - "items" : { - "description" : "Routing key", - "example" : "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV", - "pattern" : "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{43,44}$", - "type" : "string" - }, - "type" : "array" - }, - "service_endpoint" : { - "description" : "Connection endpoint", - "example" : "http://192.168.56.102:8020", - "type" : "string" - } - }, - "type" : "object" - }, "CreateKeyRequest" : { "properties" : { "alg" : { @@ -8613,11 +8502,53 @@ }, "type" : "object" }, + "CreateRequest" : { + "properties" : { + "features" : { + "additionalProperties" : { + "type" : "object" + }, + "description" : "Additional features to enable for the did.", + "example" : "{}", + "type" : "object" + }, + "options" : { + "additionalProperties" : { + "type" : "object" + }, + "description" : "Additional configuration options", + "example" : { + "did" : "did:indy:WRfXPg8dantKVubE3HX8pw", + "key_type" : "ed25519", + "seed" : "000000000000000000000000Trustee1" + }, + "type" : "object" + } + }, + "type" : "object" + }, + "CreateResponse" : { + "properties" : { + "did" : { + "description" : "DID created", + "example" : "did:indy:DFZgMggBEXcZFVQ2ZBTwdr", + "type" : "string" + }, + "verkey" : { + "description" : "Verification key", + "example" : "BnSWTUQmdYCewSGFrRUhT6LmKdcCcSzRGqWXMPnEP168", + "type" : "string" + } + }, + "type" : "object" + }, "CreateWalletRequest" : { "properties" : { "extra_settings" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Agent config key-value pairs", - "properties" : { }, "type" : "object" }, "image_url" : { @@ -8690,8 +8621,10 @@ "type" : "string" }, "settings" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Settings for this wallet.", - "properties" : { }, "type" : "object" }, "state" : { @@ -8826,7 +8759,9 @@ "CredDefResult" : { "properties" : { "credential_definition_metadata" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "credential_definition_state" : { @@ -8836,7 +8771,9 @@ "type" : "string" }, "registration_metadata" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" } }, @@ -8919,7 +8856,9 @@ "type" : "string" }, "r" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "rctxt" : { @@ -9071,8 +9010,10 @@ "CredRevIndyRecordsResult" : { "properties" : { "rev_reg_delta" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Indy revocation registry delta", - "properties" : { }, "type" : "object" } }, @@ -9081,8 +9022,10 @@ "CredRevIndyRecordsResultSchemaAnoncreds" : { "properties" : { "rev_reg_delta" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Indy revocation registry delta", - "properties" : { }, "type" : "object" } }, @@ -9198,9 +9141,21 @@ "type" : "string" }, "type" : "array" + }, + "validFrom" : { + "description" : "The valid from date", + "example" : "2010-01-01T19:23:24Z", + "pattern" : "^([0-9]{4})-([0-9]{2})-([0-9]{2})([Tt ]([0-9]{2}):([0-9]{2}):([0-9]{2})(\\.[0-9]+)?)?(([Zz]|([+-])([0-9]{2}):([0-9]{2})))?$", + "type" : "string" + }, + "validUntil" : { + "description" : "The valid until date", + "example" : "2010-01-01T19:23:24Z", + "pattern" : "^([0-9]{4})-([0-9]{2})-([0-9]{2})([Tt ]([0-9]{2}):([0-9]{2}):([0-9]{2})(\\.[0-9]+)?)?(([Zz]|([+-])([0-9]{2}):([0-9]{2})))?$", + "type" : "string" } }, - "required" : [ "@context", "credentialSubject", "issuanceDate", "issuer", "type" ], + "required" : [ "@context", "credentialSubject", "issuer", "type" ], "type" : "object" }, "CredentialDefinition" : { @@ -9376,8 +9331,8 @@ "$ref" : "#/components/schemas/CredentialPreview" }, "issuer_did" : { - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "schema_id" : { @@ -9386,8 +9341,8 @@ "type" : "string" }, "schema_issuer_did" : { - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "schema_name" : { @@ -9418,7 +9373,7 @@ "did" : { "description" : "DID of interest", "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", "type" : "string" }, "key_type" : { @@ -9428,8 +9383,10 @@ "type" : "string" }, "metadata" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Additional metadata associated with the DID", - "properties" : { }, "type" : "object" }, "method" : { @@ -9480,7 +9437,7 @@ "did" : { "description" : "Specify final value of the did (including did:: prefix)if the method supports or requires so.", "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", "type" : "string" }, "key_type" : { @@ -9497,8 +9454,8 @@ "properties" : { "did" : { "description" : "DID of interest", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "endpoint" : { @@ -9515,8 +9472,8 @@ "properties" : { "did" : { "description" : "DID of interest", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "endpoint" : { @@ -9597,7 +9554,7 @@ "did" : { "description" : "DID of exchange", "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", "type" : "string" }, "did_doc~attach" : { @@ -9699,15 +9656,20 @@ "$ref" : "#/components/schemas/PresentationDefinition" }, "record_ids" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Mapping of input_descriptor id to list of stored W3C credential record_id", "example" : { "" : [ "", "" ], "" : [ "" ] }, - "properties" : { }, "type" : "object" }, "reveal_doc" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "reveal doc [JSON-LD frame] dict used to derive the credential when selective disclosure is required", "example" : { "@context" : [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/bbs/v1" ], @@ -9726,7 +9688,6 @@ "issuer" : { }, "type" : [ "VerifiableCredential", "LabReport" ] }, - "properties" : { }, "type" : "object" } }, @@ -9888,8 +9849,10 @@ "Doc" : { "properties" : { "credential" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Credential to sign", - "properties" : { }, "type" : "object" }, "options" : { @@ -9906,7 +9869,9 @@ "DocumentVerificationResult" : { "properties" : { "document" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "errors" : { @@ -10076,11 +10041,15 @@ "type" : "string" }, "credential_definitions_metadata" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "resolution_metadata" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" } }, @@ -10137,7 +10106,9 @@ "GetSchemaResult" : { "properties" : { "resolution_metadata" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "schema" : { @@ -10149,7 +10120,9 @@ "type" : "string" }, "schema_metadata" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" } }, @@ -10308,13 +10281,17 @@ "IndyCredRequest" : { "properties" : { "blinded_ms" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Blinded master secret", - "properties" : { }, "type" : "object" }, "blinded_ms_correctness_proof" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Blinded master secret correctness proof", - "properties" : { }, "type" : "object" }, "cred_def_id" : { @@ -10347,9 +10324,11 @@ "type" : "string" }, "rev_reg" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Revocation registry state", "nullable" : true, - "properties" : { }, "type" : "object" }, "rev_reg_id" : { @@ -10366,13 +10345,17 @@ "type" : "string" }, "signature" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Credential signature", - "properties" : { }, "type" : "object" }, "signature_correctness_proof" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Credential signature correctness proof", - "properties" : { }, "type" : "object" }, "values" : { @@ -10383,9 +10366,11 @@ "type" : "object" }, "witness" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Witness for revocation proof", "nullable" : true, - "properties" : { }, "type" : "object" } }, @@ -11001,13 +10986,17 @@ "type" : "object" }, "self_attested_attrs" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Proof requested proof self-attested attributes", - "properties" : { }, "type" : "object" }, "unrevealed_attrs" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Unrevealed attributes", - "properties" : { }, "type" : "object" } }, @@ -11285,8 +11274,10 @@ "type" : "string" }, "metadata" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Metadata dictionary", - "properties" : { }, "type" : "object" }, "name" : { @@ -11370,8 +11361,10 @@ "type" : "string" }, "metadata" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Optional metadata to attach to the connection created with the invitation", - "properties" : { }, "type" : "object" }, "my_label" : { @@ -11534,25 +11527,6 @@ "InvitationRecordResponse" : { "type" : "object" }, - "InvitationResult" : { - "properties" : { - "connection_id" : { - "description" : "Connection identifier", - "example" : "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "type" : "string" - }, - "invitation" : { - "$ref" : "#/components/schemas/ConnectionInvitation" - }, - "invitation_url" : { - "description" : "Invitation URL", - "example" : "http://192.168.56.101:8020/invite?c_i=eyJAdHlwZSI6Li4ufQ==", - "type" : "string" - } - }, - "required" : [ "connection_id", "invitation", "invitation_url" ], - "type" : "object" - }, "IssueCredentialModuleResponse" : { "type" : "object" }, @@ -11698,8 +11672,8 @@ }, "issuer_did" : { "description" : "Issuer DID", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "max_cred_num" : { @@ -11783,15 +11757,19 @@ "did" : { "description" : "DID of interest", "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", "type" : "string" }, "headers" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "payload" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "verificationMethod" : { @@ -11821,8 +11799,10 @@ "type" : "string" }, "headers" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Headers from verified JWT.", - "properties" : { }, "type" : "object" }, "kid" : { @@ -11830,8 +11810,10 @@ "type" : "string" }, "payload" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Payload from verified JWT", - "properties" : { }, "type" : "object" }, "valid" : { @@ -11866,11 +11848,13 @@ "type" : "string" }, "filter" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Query dictionary object", "example" : { "filter" : { } }, - "properties" : { }, "type" : "object" }, "paginate" : { @@ -11886,8 +11870,10 @@ "KeylistQueryFilterRequest" : { "properties" : { "filter" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Filter for keylist query", - "properties" : { }, "type" : "object" } }, @@ -12589,7 +12575,9 @@ }, "verifiableCredential" : { "items" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "type" : "array" @@ -12710,13 +12698,15 @@ "ProfileSettings" : { "properties" : { "settings" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Profile settings dict", "example" : { "debug.invite_public" : true, "log.level" : "INFO", "public_invites" : false }, - "properties" : { }, "type" : "object" } }, @@ -12728,7 +12718,9 @@ "type" : "string" }, "proof" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "purpose_result" : { @@ -12853,7 +12845,9 @@ "PurposeResult" : { "properties" : { "controller" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "error" : { @@ -12939,64 +12933,6 @@ }, "type" : "object" }, - "ReceiveInvitationRequest" : { - "properties" : { - "@id" : { - "description" : "Message identifier", - "example" : "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "type" : "string" - }, - "@type" : { - "description" : "Message type", - "example" : "https://didcomm.org/my-family/1.0/my-message-type", - "type" : "string" - }, - "did" : { - "description" : "DID for connection invitation", - "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", - "type" : "string" - }, - "imageUrl" : { - "description" : "Optional image URL for connection invitation", - "example" : "http://192.168.56.101/img/logo.jpg", - "format" : "url", - "nullable" : true, - "type" : "string" - }, - "label" : { - "description" : "Optional label for connection invitation", - "example" : "Bob", - "type" : "string" - }, - "recipientKeys" : { - "description" : "List of recipient keys", - "items" : { - "description" : "Recipient public key", - "example" : "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV", - "pattern" : "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{43,44}$", - "type" : "string" - }, - "type" : "array" - }, - "routingKeys" : { - "description" : "List of routing keys", - "items" : { - "description" : "Routing key", - "example" : "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV", - "pattern" : "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{43,44}$", - "type" : "string" - }, - "type" : "array" - }, - "serviceEndpoint" : { - "description" : "Service endpoint at which to reach this agent", - "example" : "http://192.168.56.101:8020", - "type" : "string" - } - }, - "type" : "object" - }, "RemoveWalletRequest" : { "properties" : { "wallet_key" : { @@ -13010,13 +12946,17 @@ "ResolutionResult" : { "properties" : { "did_document" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "DID Document", - "properties" : { }, "type" : "object" }, "metadata" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Resolution metadata", - "properties" : { }, "type" : "object" } }, @@ -13090,11 +13030,15 @@ "type" : "string" }, "registration_metadata" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "revocation_list_metadata" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "revocation_list_state" : { @@ -13195,11 +13139,15 @@ "type" : "string" }, "registration_metadata" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "revocation_registry_definition_metadata" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "revocation_registry_definition_state" : { @@ -13236,8 +13184,10 @@ "type" : "integer" }, "publicKeys" : { + "additionalProperties" : { + "type" : "object" + }, "example" : "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV", - "properties" : { }, "type" : "object" }, "tailsHash" : { @@ -13304,18 +13254,24 @@ "RevRegWalletUpdatedResult" : { "properties" : { "accum_calculated" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Calculated accumulator for phantom revocations", - "properties" : { }, "type" : "object" }, "accum_fixed" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Applied ledger transaction to fix revocations", - "properties" : { }, "type" : "object" }, "rev_reg_delta" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Indy revocation registry delta", - "properties" : { }, "type" : "object" } }, @@ -13324,18 +13280,24 @@ "RevRegWalletUpdatedResultSchemaAnoncreds" : { "properties" : { "accum_calculated" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Calculated accumulator for phantom revocations", - "properties" : { }, "type" : "object" }, "accum_fixed" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Applied ledger transaction to fix revocations", - "properties" : { }, "type" : "object" }, "rev_reg_delta" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Indy revocation registry delta", - "properties" : { }, "type" : "object" } }, @@ -13369,9 +13331,6 @@ }, "type" : "object" }, - "RevocationAnoncredsModuleResponse" : { - "type" : "object" - }, "RevocationModuleResponse" : { "type" : "object" }, @@ -13539,11 +13498,13 @@ "did" : { "description" : "DID of interest", "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$", "type" : "string" }, "headers" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "non_sd_list" : { @@ -13555,7 +13516,9 @@ "type" : "array" }, "payload" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "verificationMethod" : { @@ -13598,8 +13561,10 @@ "type" : "string" }, "headers" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Headers from verified JWT.", - "properties" : { }, "type" : "object" }, "kid" : { @@ -13607,8 +13572,10 @@ "type" : "string" }, "payload" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Payload from verified JWT", - "properties" : { }, "type" : "object" }, "valid" : { @@ -13714,11 +13681,15 @@ "type" : "string" }, "registration_metadata" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "schema_metadata" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "schema_state" : { @@ -13895,8 +13866,10 @@ "type" : "string" }, "signed_doc" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Signed document", - "properties" : { }, "type" : "object" } }, @@ -14136,6 +14109,9 @@ }, "messages_attach" : { "items" : { + "additionalProperties" : { + "type" : "object" + }, "example" : { "@id" : "143c458d-1b1c-40c7-ab85-4d16808ddf0a", "data" : { @@ -14143,12 +14119,14 @@ }, "mime-type" : "application/json" }, - "properties" : { }, "type" : "object" }, "type" : "array" }, "meta_data" : { + "additionalProperties" : { + "type" : "object" + }, "example" : { "context" : { "param1" : "param1_value", @@ -14159,11 +14137,13 @@ "other" : "other_value" } ] }, - "properties" : { }, "type" : "object" }, "signature_request" : { "items" : { + "additionalProperties" : { + "type" : "object" + }, "example" : { "author_goal_code" : "aries.transaction.ledger.write", "context" : "did:sov", @@ -14171,20 +14151,21 @@ "signature_type" : "default", "signer_goal_code" : "aries.transaction.endorse" }, - "properties" : { }, "type" : "object" }, "type" : "array" }, "signature_response" : { "items" : { + "additionalProperties" : { + "type" : "object" + }, "example" : { "context" : "did:sov", "message_id" : "3fa85f64-5717-4562-b3fc-2c963f66afa6", "method" : "add-signature", "signer_goal_code" : "aries.transaction.refuse" }, - "properties" : { }, "type" : "object" }, "type" : "array" @@ -14200,10 +14181,12 @@ "type" : "string" }, "timing" : { + "additionalProperties" : { + "type" : "object" + }, "example" : { "expires_time" : "2020-12-13T17:29:06+0000" }, - "properties" : { }, "type" : "object" }, "trace" : { @@ -14352,13 +14335,15 @@ "UpdateProfileSettings" : { "properties" : { "extra_settings" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Agent config key-value pairs", "example" : { "ACAPY_INVITE_PUBLIC" : true, "log-level" : "INFO", "public-invites" : false }, - "properties" : { }, "type" : "object" } }, @@ -14367,8 +14352,10 @@ "UpdateWalletRequest" : { "properties" : { "extra_settings" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Agent config key-value pairs", - "properties" : { }, "type" : "object" }, "image_url" : { @@ -14468,8 +14455,8 @@ }, "issuer_did" : { "description" : "Credential issuer DID", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "schema_id" : { @@ -14480,8 +14467,8 @@ }, "schema_issuer_did" : { "description" : "Schema issuer DID", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "schema_name" : { @@ -14583,8 +14570,10 @@ "type" : "object" }, "credential_request_metadata" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "(Indy) credential request metadata", - "properties" : { }, "type" : "object" }, "error_msg" : { @@ -14757,8 +14746,8 @@ }, "issuer_did" : { "description" : "Credential issuer DID", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "schema_id" : { @@ -14769,8 +14758,8 @@ }, "schema_issuer_did" : { "description" : "Schema issuer DID", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "schema_name" : { @@ -14819,8 +14808,8 @@ }, "issuer_did" : { "description" : "Credential issuer DID", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "schema_id" : { @@ -14831,8 +14820,8 @@ }, "schema_issuer_did" : { "description" : "Schema issuer DID", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "schema_name" : { @@ -15427,19 +15416,27 @@ "V20CredExRecordByFormat" : { "properties" : { "cred_issue" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "cred_offer" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "cred_proposal" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "cred_request" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" } }, @@ -15490,8 +15487,10 @@ "type" : "string" }, "cred_request_metadata" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Credential request metadata for indy holder", - "properties" : { }, "type" : "object" }, "cred_rev_id" : { @@ -15647,8 +15646,8 @@ }, "issuer_did" : { "description" : "Credential issuer DID", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "schema_id" : { @@ -15659,8 +15658,8 @@ }, "schema_issuer_did" : { "description" : "Schema issuer DID", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "schema_name" : { @@ -15700,8 +15699,8 @@ }, "issuer_did" : { "description" : "Credential issuer DID", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "schema_id" : { @@ -15712,8 +15711,8 @@ }, "schema_issuer_did" : { "description" : "Schema issuer DID", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$", "type" : "string" }, "schema_name" : { @@ -16383,15 +16382,21 @@ "V20PresExRecordByFormat" : { "properties" : { "pres" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "pres_proposal" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "pres_request" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" } }, @@ -16697,8 +16702,10 @@ "type" : "object" }, "cred_value" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "(JSON-serializable) credential value", - "properties" : { }, "type" : "object" }, "expanded_types" : { @@ -16825,9 +16832,21 @@ "type" : "string" }, "type" : "array" + }, + "validFrom" : { + "description" : "The valid from date", + "example" : "2010-01-01T19:23:24Z", + "pattern" : "^([0-9]{4})-([0-9]{2})-([0-9]{2})([Tt ]([0-9]{2}):([0-9]{2}):([0-9]{2})(\\.[0-9]+)?)?(([Zz]|([+-])([0-9]{2}):([0-9]{2})))?$", + "type" : "string" + }, + "validUntil" : { + "description" : "The valid until date", + "example" : "2010-01-01T19:23:24Z", + "pattern" : "^([0-9]{4})-([0-9]{2})-([0-9]{2})([Tt ]([0-9]{2}):([0-9]{2}):([0-9]{2})(\\.[0-9]+)?)?(([Zz]|([+-])([0-9]{2}):([0-9]{2})))?$", + "type" : "string" } }, - "required" : [ "@context", "credentialSubject", "issuanceDate", "issuer", "proof", "type" ], + "required" : [ "@context", "credentialSubject", "issuer", "proof", "type" ], "type" : "object" }, "VerifiablePresentation" : { @@ -16876,7 +16895,9 @@ }, "verifiableCredential" : { "items" : { - "properties" : { }, + "additionalProperties" : { + "type" : "object" + }, "type" : "object" }, "type" : "array" @@ -16907,6 +16928,9 @@ "VerifyDiRequest" : { "properties" : { "securedDocument" : { + "additionalProperties" : { + "type" : "object" + }, "example" : { "hello" : "world", "proof" : [ { @@ -16917,7 +16941,6 @@ "proofValue" : "zHtda8vV7kJQUPfSKiTGSQDhZfhkgtpnVziT7cdEzhu fjPjbeRmysHvizMJEox1eHR7xUGzNUj1V4yaKiLw7UA6E" } ] }, - "properties" : { }, "type" : "object" } }, @@ -17081,8 +17104,10 @@ "type" : "string" }, "settings" : { + "additionalProperties" : { + "type" : "object" + }, "description" : "Settings for this wallet.", - "properties" : { }, "type" : "object" }, "state" : { diff --git a/open-api/swagger.json b/open-api/swagger.json index 26396f8bac..74b1c839e3 100644 --- a/open-api/swagger.json +++ b/open-api/swagger.json @@ -1,7 +1,7 @@ { "swagger" : "2.0", "info" : { - "version" : "v1.2.1", + "version" : "v1.3.0rc0", "title" : "Aries Cloud Agent" }, "tags" : [ { @@ -44,11 +44,7 @@ } }, { "name" : "connection", - "description" : "Connection management", - "externalDocs" : { - "description" : "Specification", - "url" : "https://github.com/hyperledger/aries-rfcs/tree/9b0aaa39df7e8bd434126c4b33c097aae78d65bf/features/0160-connection-protocol" - } + "description" : "Connection management" }, { "name" : "credential-definition", "description" : "Credential definition operations", @@ -63,6 +59,13 @@ "description" : "Overview", "url" : "https://w3c.github.io/vc-data-model/#credentials" } + }, { + "name" : "did", + "description" : "Endpoints for managing dids", + "externalDocs" : { + "description" : "Specification", + "url" : "https://www.w3.org/TR/did-core/" + } }, { "name" : "did-exchange", "description" : "Connection management via DID exchange", @@ -426,13 +429,13 @@ "description" : "Revocation Registry identifier", "required" : true, "type" : "string", - "pattern" : "^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}):4:([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}):3:CL:(([1-9][0-9]*)|([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}:2:.+:[0-9.]+))(:.+)?:CL_ACCUM:(.+$)" + "pattern" : "^(.+$)" } ], "responses" : { "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/RevocationModuleResponse" + "$ref" : "#/definitions/AnoncredsRevocationModuleResponse" } } } @@ -449,13 +452,13 @@ "description" : "Revocation Registry identifier", "required" : true, "type" : "string", - "pattern" : "^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}):4:([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}):3:CL:(([1-9][0-9]*)|([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}:2:.+:[0-9.]+))(:.+)?:CL_ACCUM:(.+$)" + "pattern" : "^(.+$)" } ], "responses" : { "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/RevocationModuleResponse" + "$ref" : "#/definitions/AnoncredsRevocationModuleResponse" } } } @@ -811,7 +814,7 @@ "200" : { "description" : "tails file", "schema" : { - "$ref" : "#/definitions/RevocationAnoncredsModuleResponse" + "$ref" : "#/definitions/AnoncredsRevocationModuleResponse" } } } @@ -834,7 +837,7 @@ "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/RevocationAnoncredsModuleResponse" + "$ref" : "#/definitions/AnoncredsRevocationModuleResponse" } } } @@ -958,7 +961,14 @@ "description" : "Connection protocol used", "required" : false, "type" : "string", - "enum" : [ "connections/1.0", "didexchange/1.0", "didexchange/1.1" ] + "enum" : [ "didexchange/1.0", "didexchange/1.1" ] + }, { + "name" : "descending", + "in" : "query", + "description" : "Order results in descending order if true", + "required" : false, + "type" : "boolean", + "default" : false }, { "name" : "invitation_key", "in" : "query", @@ -978,21 +988,32 @@ "description" : "Number of results to return", "required" : false, "type" : "integer", - "default" : 100 + "default" : 100, + "maximum" : 10000, + "minimum" : 1 }, { "name" : "my_did", "in" : "query", "description" : "My DID", "required" : false, "type" : "string", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" }, { "name" : "offset", "in" : "query", "description" : "Offset for pagination", "required" : false, "type" : "integer", - "default" : 0 + "default" : 0, + "minimum" : 0 + }, { + "name" : "order_by", + "in" : "query", + "description" : "The column to order results by. Only \"id\" is currently supported.", + "required" : false, + "type" : "string", + "default" : "id", + "enum" : [ "id" ] }, { "name" : "state", "in" : "query", @@ -1006,14 +1027,14 @@ "description" : "Their DID", "required" : false, "type" : "string", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" }, { "name" : "their_public_did", "in" : "query", "description" : "Their Public DID", "required" : false, "type" : "string", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" }, { "name" : "their_role", "in" : "query", @@ -1032,54 +1053,6 @@ } } }, - "/connections/create-invitation" : { - "post" : { - "tags" : [ "connection" ], - "summary" : "Create a new connection invitation", - "produces" : [ "application/json" ], - "parameters" : [ { - "in" : "body", - "name" : "body", - "required" : false, - "schema" : { - "$ref" : "#/definitions/CreateInvitationRequest" - } - }, { - "name" : "alias", - "in" : "query", - "description" : "Alias", - "required" : false, - "type" : "string" - }, { - "name" : "auto_accept", - "in" : "query", - "description" : "Auto-accept connection (defaults to configuration)", - "required" : false, - "type" : "boolean" - }, { - "name" : "multi_use", - "in" : "query", - "description" : "Create invitation for multiple use (default false)", - "required" : false, - "type" : "boolean" - }, { - "name" : "public", - "in" : "query", - "description" : "Create invitation from public DID (default false)", - "required" : false, - "type" : "boolean" - } ], - "deprecated" : true, - "responses" : { - "200" : { - "description" : "", - "schema" : { - "$ref" : "#/definitions/InvitationResult" - } - } - } - } - }, "/connections/create-static" : { "post" : { "tags" : [ "connection" ], @@ -1103,49 +1076,6 @@ } } }, - "/connections/receive-invitation" : { - "post" : { - "tags" : [ "connection" ], - "summary" : "Receive a new connection invitation", - "produces" : [ "application/json" ], - "parameters" : [ { - "in" : "body", - "name" : "body", - "required" : false, - "schema" : { - "$ref" : "#/definitions/ReceiveInvitationRequest" - } - }, { - "name" : "alias", - "in" : "query", - "description" : "Alias", - "required" : false, - "type" : "string" - }, { - "name" : "auto_accept", - "in" : "query", - "description" : "Auto-accept connection (defaults to configuration)", - "required" : false, - "type" : "boolean" - }, { - "name" : "mediation_id", - "in" : "query", - "description" : "Identifier for active mediation record to be used", - "required" : false, - "type" : "string", - "pattern" : "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}" - } ], - "deprecated" : true, - "responses" : { - "200" : { - "description" : "", - "schema" : { - "$ref" : "#/definitions/ConnRecord" - } - } - } - } - }, "/connections/{conn_id}" : { "get" : { "tags" : [ "connection" ], @@ -1188,79 +1118,6 @@ } } }, - "/connections/{conn_id}/accept-invitation" : { - "post" : { - "tags" : [ "connection" ], - "summary" : "Accept a stored connection invitation", - "produces" : [ "application/json" ], - "parameters" : [ { - "name" : "conn_id", - "in" : "path", - "description" : "Connection identifier", - "required" : true, - "type" : "string" - }, { - "name" : "mediation_id", - "in" : "query", - "description" : "Identifier for active mediation record to be used", - "required" : false, - "type" : "string", - "pattern" : "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}" - }, { - "name" : "my_endpoint", - "in" : "query", - "description" : "My URL endpoint", - "required" : false, - "type" : "string", - "pattern" : "^[A-Za-z0-9\\.\\-\\+]+://([A-Za-z0-9][.A-Za-z0-9-_]+[A-Za-z0-9])+(:[1-9][0-9]*)?(/[^?&#]+)?$" - }, { - "name" : "my_label", - "in" : "query", - "description" : "Label for connection", - "required" : false, - "type" : "string" - } ], - "deprecated" : true, - "responses" : { - "200" : { - "description" : "", - "schema" : { - "$ref" : "#/definitions/ConnRecord" - } - } - } - } - }, - "/connections/{conn_id}/accept-request" : { - "post" : { - "tags" : [ "connection" ], - "summary" : "Accept a stored connection request", - "produces" : [ "application/json" ], - "parameters" : [ { - "name" : "conn_id", - "in" : "path", - "description" : "Connection identifier", - "required" : true, - "type" : "string" - }, { - "name" : "my_endpoint", - "in" : "query", - "description" : "My URL endpoint", - "required" : false, - "type" : "string", - "pattern" : "^[A-Za-z0-9\\.\\-\\+]+://([A-Za-z0-9][.A-Za-z0-9-_]+[A-Za-z0-9])+(:[1-9][0-9]*)?(/[^?&#]+)?$" - } ], - "deprecated" : true, - "responses" : { - "200" : { - "description" : "", - "schema" : { - "$ref" : "#/definitions/ConnRecord" - } - } - } - } - }, "/connections/{conn_id}/endpoints" : { "get" : { "tags" : [ "connection" ], @@ -1483,7 +1340,7 @@ "description" : "Issuer DID", "required" : false, "type" : "string", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, { "name" : "schema_id", "in" : "query", @@ -1497,7 +1354,7 @@ "description" : "Schema issuer DID", "required" : false, "type" : "string", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, { "name" : "schema_name", "in" : "query", @@ -1728,13 +1585,16 @@ "in" : "query", "description" : "Number of results to return", "required" : false, - "type" : "integer" + "type" : "integer", + "maximum" : 10000, + "minimum" : 1 }, { "name" : "offset", "in" : "query", "description" : "Offset for pagination", "required" : false, - "type" : "integer" + "type" : "integer", + "minimum" : 0 }, { "name" : "start", "in" : "query", @@ -1835,6 +1695,29 @@ } } }, + "/did/indy/create" : { + "post" : { + "tags" : [ "did" ], + "summary" : "Create a did:indy", + "produces" : [ "application/json" ], + "parameters" : [ { + "in" : "body", + "name" : "body", + "required" : false, + "schema" : { + "$ref" : "#/definitions/CreateRequest" + } + } ], + "responses" : { + "200" : { + "description" : "", + "schema" : { + "$ref" : "#/definitions/CreateResponse" + } + } + } + } + }, "/didexchange/create-request" : { "post" : { "tags" : [ "did-exchange" ], @@ -1846,7 +1729,7 @@ "description" : "Qualified public DID to which to request connection", "required" : true, "type" : "string", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" }, { "name" : "alias", "in" : "query", @@ -2266,20 +2149,38 @@ "description" : "Connection identifier", "required" : false, "type" : "string" + }, { + "name" : "descending", + "in" : "query", + "description" : "Order results in descending order if true", + "required" : false, + "type" : "boolean", + "default" : false }, { "name" : "limit", "in" : "query", "description" : "Number of results to return", "required" : false, "type" : "integer", - "default" : 100 + "default" : 100, + "maximum" : 10000, + "minimum" : 1 }, { "name" : "offset", "in" : "query", "description" : "Offset for pagination", "required" : false, "type" : "integer", - "default" : 0 + "default" : 0, + "minimum" : 0 + }, { + "name" : "order_by", + "in" : "query", + "description" : "The column to order results by. Only \"id\" is currently supported.", + "required" : false, + "type" : "string", + "default" : "id", + "enum" : [ "id" ] }, { "name" : "role", "in" : "query", @@ -2656,20 +2557,38 @@ "description" : "Connection identifier", "required" : false, "type" : "string" + }, { + "name" : "descending", + "in" : "query", + "description" : "Order results in descending order if true", + "required" : false, + "type" : "boolean", + "default" : false }, { "name" : "limit", "in" : "query", "description" : "Number of results to return", "required" : false, "type" : "integer", - "default" : 100 + "default" : 100, + "maximum" : 10000, + "minimum" : 1 }, { "name" : "offset", "in" : "query", "description" : "Offset for pagination", "required" : false, "type" : "integer", - "default" : 0 + "default" : 0, + "minimum" : 0 + }, { + "name" : "order_by", + "in" : "query", + "description" : "The column to order results by. Only \"id\" is currently supported.", + "required" : false, + "type" : "string", + "default" : "id", + "enum" : [ "id" ] }, { "name" : "role", "in" : "query", @@ -3050,7 +2969,7 @@ "description" : "DID of interest", "required" : true, "type" : "string", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, { "name" : "endpoint_type", "in" : "query", @@ -3080,7 +2999,7 @@ "description" : "DID of interest", "required" : true, "type" : "string", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" } ], "responses" : { "200" : { @@ -3103,7 +3022,7 @@ "description" : "DID of interest", "required" : true, "type" : "string", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" } ], "responses" : { "200" : { @@ -3158,7 +3077,7 @@ "description" : "DID to register", "required" : true, "type" : "string", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, { "name" : "verkey", "in" : "query", @@ -3747,19 +3666,37 @@ "summary" : "Query subwallets", "produces" : [ "application/json" ], "parameters" : [ { + "name" : "descending", + "in" : "query", + "description" : "Order results in descending order if true", + "required" : false, + "type" : "boolean", + "default" : false + }, { "name" : "limit", "in" : "query", "description" : "Number of results to return", "required" : false, "type" : "integer", - "default" : 100 + "default" : 100, + "maximum" : 10000, + "minimum" : 1 }, { "name" : "offset", "in" : "query", "description" : "Offset for pagination", "required" : false, "type" : "integer", - "default" : 0 + "default" : 0, + "minimum" : 0 + }, { + "name" : "order_by", + "in" : "query", + "description" : "The column to order results by. Only \"id\" is currently supported.", + "required" : false, + "type" : "string", + "default" : "id", + "enum" : [ "id" ] }, { "name" : "wallet_name", "in" : "query", @@ -3939,20 +3876,38 @@ "description" : "Connection identifier", "required" : false, "type" : "string" + }, { + "name" : "descending", + "in" : "query", + "description" : "Order results in descending order if true", + "required" : false, + "type" : "boolean", + "default" : false }, { "name" : "limit", "in" : "query", "description" : "Number of results to return", "required" : false, "type" : "integer", - "default" : 100 + "default" : 100, + "maximum" : 10000, + "minimum" : 1 }, { "name" : "offset", "in" : "query", "description" : "Offset for pagination", "required" : false, "type" : "integer", - "default" : 0 + "default" : 0, + "minimum" : 0 + }, { + "name" : "order_by", + "in" : "query", + "description" : "The column to order results by. Only \"id\" is currently supported.", + "required" : false, + "type" : "string", + "default" : "id", + "enum" : [ "id" ] }, { "name" : "role", "in" : "query", @@ -4060,13 +4015,16 @@ "in" : "query", "description" : "Number of results to return", "required" : false, - "type" : "integer" + "type" : "integer", + "maximum" : 10000, + "minimum" : 1 }, { "name" : "offset", "in" : "query", "description" : "Offset for pagination", "required" : false, - "type" : "integer" + "type" : "integer", + "minimum" : 0 }, { "name" : "referent", "in" : "query", @@ -4289,20 +4247,38 @@ "description" : "Connection identifier", "required" : false, "type" : "string" + }, { + "name" : "descending", + "in" : "query", + "description" : "Order results in descending order if true", + "required" : false, + "type" : "boolean", + "default" : false }, { "name" : "limit", "in" : "query", "description" : "Number of results to return", "required" : false, "type" : "integer", - "default" : 100 + "default" : 100, + "maximum" : 10000, + "minimum" : 1 }, { "name" : "offset", "in" : "query", "description" : "Offset for pagination", "required" : false, "type" : "integer", - "default" : 0 + "default" : 0, + "minimum" : 0 + }, { + "name" : "order_by", + "in" : "query", + "description" : "The column to order results by. Only \"id\" is currently supported.", + "required" : false, + "type" : "string", + "default" : "id", + "enum" : [ "id" ] }, { "name" : "role", "in" : "query", @@ -4413,13 +4389,16 @@ "in" : "query", "description" : "Number of results to return", "required" : false, - "type" : "integer" + "type" : "integer", + "maximum" : 10000, + "minimum" : 1 }, { "name" : "offset", "in" : "query", "description" : "Offset for pagination", "required" : false, - "type" : "integer" + "type" : "integer", + "minimum" : 0 }, { "name" : "referent", "in" : "query", @@ -5243,7 +5222,7 @@ "description" : "Schema issuer DID", "required" : false, "type" : "string", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, { "name" : "schema_name", "in" : "query", @@ -5902,7 +5881,7 @@ "description" : "DID of interest", "required" : false, "type" : "string", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" }, { "name" : "key_type", "in" : "query", @@ -5975,7 +5954,7 @@ "description" : "DID of interest", "required" : true, "type" : "string", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" } ], "responses" : { "200" : { @@ -6012,7 +5991,7 @@ "description" : "DID of interest", "required" : true, "type" : "string", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" }, { "name" : "conn_id", "in" : "query", @@ -6053,7 +6032,7 @@ "description" : "DID of interest", "required" : true, "type" : "string", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" } ], "responses" : { "200" : { @@ -6304,7 +6283,7 @@ "example" : { "hello" : "world" }, - "properties" : { } + "additionalProperties" : { } }, "options" : { "$ref" : "#/definitions/AddProof_options" @@ -6320,7 +6299,7 @@ "example" : { "hello" : "world" }, - "properties" : { } + "additionalProperties" : { } } } }, @@ -6331,7 +6310,7 @@ "config" : { "type" : "object", "description" : "Configuration settings", - "properties" : { } + "additionalProperties" : { } } } }, @@ -6363,7 +6342,7 @@ "conductor" : { "type" : "object", "description" : "Conductor statistics", - "properties" : { } + "additionalProperties" : { } }, "label" : { "type" : "string", @@ -6373,7 +6352,7 @@ "timing" : { "type" : "object", "description" : "Timing results", - "properties" : { } + "additionalProperties" : { } }, "version" : { "type" : "string", @@ -6595,6 +6574,9 @@ } } }, + "AnoncredsRevocationModuleResponse" : { + "type" : "object" + }, "AttachDecorator" : { "type" : "object", "required" : [ "data" ], @@ -6764,31 +6746,31 @@ "properties" : { "di_vc" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "jwt" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "jwt_vc" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "jwt_vp" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "ldp" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "ldp_vc" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "ldp_vp" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } } } }, @@ -6845,9 +6827,9 @@ }, "connection_protocol" : { "type" : "string", - "example" : "connections/1.0", + "example" : "didexchange/1.1", "description" : "Connection protocol used", - "enum" : [ "connections/1.0", "didexchange/1.0", "didexchange/1.1" ] + "enum" : [ "didexchange/1.0", "didexchange/1.1" ] }, "created_at" : { "type" : "string", @@ -6886,7 +6868,7 @@ "type" : "string", "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", "description" : "Our DID for connection", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" }, "request_id" : { "type" : "string", @@ -6908,7 +6890,7 @@ "type" : "string", "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", "description" : "Their DID for connection", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" }, "their_label" : { "type" : "string", @@ -6934,64 +6916,6 @@ } } }, - "ConnectionInvitation" : { - "type" : "object", - "properties" : { - "@id" : { - "type" : "string", - "example" : "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "description" : "Message identifier" - }, - "@type" : { - "type" : "string", - "example" : "https://didcomm.org/my-family/1.0/my-message-type", - "description" : "Message type" - }, - "did" : { - "type" : "string", - "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", - "description" : "DID for connection invitation", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" - }, - "imageUrl" : { - "type" : "string", - "format" : "url", - "example" : "http://192.168.56.101/img/logo.jpg", - "description" : "Optional image URL for connection invitation", - "x-nullable" : true - }, - "label" : { - "type" : "string", - "example" : "Bob", - "description" : "Optional label for connection invitation" - }, - "recipientKeys" : { - "type" : "array", - "description" : "List of recipient keys", - "items" : { - "type" : "string", - "example" : "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV", - "description" : "Recipient public key", - "pattern" : "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{43,44}$" - } - }, - "routingKeys" : { - "type" : "array", - "description" : "List of routing keys", - "items" : { - "type" : "string", - "example" : "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV", - "description" : "Routing key", - "pattern" : "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{43,44}$" - } - }, - "serviceEndpoint" : { - "type" : "string", - "example" : "http://192.168.56.101:8020", - "description" : "Service endpoint at which to reach this agent" - } - } - }, "ConnectionList" : { "type" : "object", "required" : [ "results" ], @@ -7011,7 +6935,7 @@ "results" : { "type" : "object", "description" : "Dictionary of metadata associated with connection.", - "properties" : { } + "additionalProperties" : { } } } }, @@ -7022,7 +6946,7 @@ "metadata" : { "type" : "object", "description" : "Dictionary of metadata to set for connection.", - "properties" : { } + "additionalProperties" : { } } } }, @@ -7038,9 +6962,9 @@ }, "my_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "Local DID", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "my_seed" : { "type" : "string", @@ -7048,9 +6972,9 @@ }, "their_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "Remote DID", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "their_endpoint" : { "type" : "string", @@ -7078,9 +7002,9 @@ "properties" : { "my_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "Local DID", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "my_endpoint" : { "type" : "string", @@ -7099,9 +7023,9 @@ }, "their_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "Remote DID", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "their_verkey" : { "type" : "string", @@ -7149,52 +7073,6 @@ } } }, - "CreateInvitationRequest" : { - "type" : "object", - "properties" : { - "mediation_id" : { - "type" : "string", - "example" : "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "description" : "Identifier for active mediation record to be used", - "pattern" : "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}" - }, - "metadata" : { - "type" : "object", - "description" : "Optional metadata to attach to the connection created with the invitation", - "properties" : { } - }, - "my_label" : { - "type" : "string", - "example" : "Bob", - "description" : "Optional label for connection invitation" - }, - "recipient_keys" : { - "type" : "array", - "description" : "List of recipient keys", - "items" : { - "type" : "string", - "example" : "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV", - "description" : "Recipient public key", - "pattern" : "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{43,44}$" - } - }, - "routing_keys" : { - "type" : "array", - "description" : "List of routing keys", - "items" : { - "type" : "string", - "example" : "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV", - "description" : "Routing key", - "pattern" : "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{43,44}$" - } - }, - "service_endpoint" : { - "type" : "string", - "example" : "http://192.168.56.102:8020", - "description" : "Connection endpoint" - } - } - }, "CreateKeyRequest" : { "type" : "object", "properties" : { @@ -7230,13 +7108,49 @@ } } }, + "CreateRequest" : { + "type" : "object", + "properties" : { + "features" : { + "type" : "object", + "example" : "{}", + "description" : "Additional features to enable for the did.", + "additionalProperties" : { } + }, + "options" : { + "type" : "object", + "example" : { + "did" : "did:indy:WRfXPg8dantKVubE3HX8pw", + "key_type" : "ed25519", + "seed" : "000000000000000000000000Trustee1" + }, + "description" : "Additional configuration options", + "additionalProperties" : { } + } + } + }, + "CreateResponse" : { + "type" : "object", + "properties" : { + "did" : { + "type" : "string", + "example" : "did:indy:DFZgMggBEXcZFVQ2ZBTwdr", + "description" : "DID created" + }, + "verkey" : { + "type" : "string", + "example" : "BnSWTUQmdYCewSGFrRUhT6LmKdcCcSzRGqWXMPnEP168", + "description" : "Verification key" + } + } + }, "CreateWalletRequest" : { "type" : "object", "properties" : { "extra_settings" : { "type" : "object", "description" : "Agent config key-value pairs", - "properties" : { } + "additionalProperties" : { } }, "image_url" : { "type" : "string", @@ -7311,7 +7225,7 @@ "settings" : { "type" : "object", "description" : "Settings for this wallet.", - "properties" : { } + "additionalProperties" : { } }, "state" : { "type" : "string", @@ -7445,7 +7359,7 @@ "properties" : { "credential_definition_metadata" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "credential_definition_state" : { "$ref" : "#/definitions/CredDefState" @@ -7455,7 +7369,7 @@ }, "registration_metadata" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } } } }, @@ -7526,7 +7440,7 @@ }, "r" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "rctxt" : { "type" : "string", @@ -7671,7 +7585,7 @@ "rev_reg_delta" : { "type" : "object", "description" : "Indy revocation registry delta", - "properties" : { } + "additionalProperties" : { } } } }, @@ -7681,7 +7595,7 @@ "rev_reg_delta" : { "type" : "object", "description" : "Indy revocation registry delta", - "properties" : { } + "additionalProperties" : { } } } }, @@ -7734,7 +7648,7 @@ }, "Credential" : { "type" : "object", - "required" : [ "@context", "credentialSubject", "issuanceDate", "issuer", "type" ], + "required" : [ "@context", "credentialSubject", "issuer", "type" ], "properties" : { "@context" : { "type" : "array", @@ -7780,6 +7694,18 @@ "items" : { "type" : "string" } + }, + "validFrom" : { + "type" : "string", + "example" : "2010-01-01T19:23:24Z", + "description" : "The valid from date", + "pattern" : "^([0-9]{4})-([0-9]{2})-([0-9]{2})([Tt ]([0-9]{2}):([0-9]{2}):([0-9]{2})(\\.[0-9]+)?)?(([Zz]|([+-])([0-9]{2}):([0-9]{2})))?$" + }, + "validUntil" : { + "type" : "string", + "example" : "2010-01-01T19:23:24Z", + "description" : "The valid until date", + "pattern" : "^([0-9]{4})-([0-9]{2})-([0-9]{2})([Tt ]([0-9]{2}):([0-9]{2}):([0-9]{2})(\\.[0-9]+)?)?(([Zz]|([+-])([0-9]{2}):([0-9]{2})))?$" } }, "additionalProperties" : true @@ -7954,8 +7880,8 @@ }, "issuer_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "schema_id" : { "type" : "string", @@ -7964,8 +7890,8 @@ }, "schema_issuer_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "schema_name" : { "type" : "string" @@ -7997,7 +7923,7 @@ "type" : "string", "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", "description" : "DID of interest", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" }, "key_type" : { "type" : "string", @@ -8008,7 +7934,7 @@ "metadata" : { "type" : "object", "description" : "Additional metadata associated with the DID", - "properties" : { } + "additionalProperties" : { } }, "method" : { "type" : "string", @@ -8055,7 +7981,7 @@ "type" : "string", "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", "description" : "Specify final value of the did (including did:: prefix)if the method supports or requires so.", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" }, "key_type" : { "type" : "string", @@ -8071,9 +7997,9 @@ "properties" : { "did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "DID of interest", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "endpoint" : { "type" : "string", @@ -8089,9 +8015,9 @@ "properties" : { "did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "DID of interest", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "endpoint" : { "type" : "string", @@ -8172,7 +8098,7 @@ "type" : "string", "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", "description" : "DID of exchange", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" }, "did_doc~attach" : { "$ref" : "#/definitions/DIDXRequest_did_docattach" @@ -8274,7 +8200,7 @@ "" : [ "" ] }, "description" : "Mapping of input_descriptor id to list of stored W3C credential record_id", - "properties" : { } + "additionalProperties" : { } }, "reveal_doc" : { "type" : "object", @@ -8296,7 +8222,7 @@ "type" : [ "VerifiableCredential", "LabReport" ] }, "description" : "reveal doc [JSON-LD frame] dict used to derive the credential when selective disclosure is required", - "properties" : { } + "additionalProperties" : { } } } }, @@ -8458,7 +8384,7 @@ "credential" : { "type" : "object", "description" : "Credential to sign", - "properties" : { } + "additionalProperties" : { } }, "options" : { "$ref" : "#/definitions/Doc_options" @@ -8471,7 +8397,7 @@ "properties" : { "document" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "errors" : { "type" : "array", @@ -8630,11 +8556,11 @@ }, "credential_definitions_metadata" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "resolution_metadata" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } } } }, @@ -8691,7 +8617,7 @@ "properties" : { "resolution_metadata" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "schema" : { "$ref" : "#/definitions/AnonCredsSchema" @@ -8703,7 +8629,7 @@ }, "schema_metadata" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } } } }, @@ -8852,12 +8778,12 @@ "blinded_ms" : { "type" : "object", "description" : "Blinded master secret", - "properties" : { } + "additionalProperties" : { } }, "blinded_ms_correctness_proof" : { "type" : "object", "description" : "Blinded master secret correctness proof", - "properties" : { } + "additionalProperties" : { } }, "cred_def_id" : { "type" : "string", @@ -8891,7 +8817,7 @@ "rev_reg" : { "type" : "object", "description" : "Revocation registry state", - "properties" : { }, + "additionalProperties" : { }, "x-nullable" : true }, "rev_reg_id" : { @@ -8910,12 +8836,12 @@ "signature" : { "type" : "object", "description" : "Credential signature", - "properties" : { } + "additionalProperties" : { } }, "signature_correctness_proof" : { "type" : "object", "description" : "Credential signature correctness proof", - "properties" : { } + "additionalProperties" : { } }, "values" : { "type" : "object", @@ -8927,7 +8853,7 @@ "witness" : { "type" : "object", "description" : "Witness for revocation proof", - "properties" : { }, + "additionalProperties" : { }, "x-nullable" : true } } @@ -9518,12 +9444,12 @@ "self_attested_attrs" : { "type" : "object", "description" : "Proof requested proof self-attested attributes", - "properties" : { } + "additionalProperties" : { } }, "unrevealed_attrs" : { "type" : "object", "description" : "Unrevealed attributes", - "properties" : { } + "additionalProperties" : { } } } }, @@ -9790,7 +9716,7 @@ "metadata" : { "type" : "object", "description" : "Metadata dictionary", - "properties" : { } + "additionalProperties" : { } }, "name" : { "type" : "string", @@ -9858,7 +9784,7 @@ "metadata" : { "type" : "object", "description" : "Optional metadata to attach to the connection created with the invitation", - "properties" : { } + "additionalProperties" : { } }, "my_label" : { "type" : "string", @@ -10014,25 +9940,6 @@ "InvitationRecordResponse" : { "type" : "object" }, - "InvitationResult" : { - "type" : "object", - "required" : [ "connection_id", "invitation", "invitation_url" ], - "properties" : { - "connection_id" : { - "type" : "string", - "example" : "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "description" : "Connection identifier" - }, - "invitation" : { - "$ref" : "#/definitions/ConnectionInvitation" - }, - "invitation_url" : { - "type" : "string", - "example" : "http://192.168.56.101:8020/invite?c_i=eyJAdHlwZSI6Li4ufQ==", - "description" : "Invitation URL" - } - } - }, "IssueCredentialModuleResponse" : { "type" : "object" }, @@ -10179,9 +10086,9 @@ }, "issuer_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "Issuer DID", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "max_cred_num" : { "type" : "integer", @@ -10258,15 +10165,15 @@ "type" : "string", "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", "description" : "DID of interest", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" }, "headers" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "payload" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "verificationMethod" : { "type" : "string", @@ -10297,7 +10204,7 @@ "headers" : { "type" : "object", "description" : "Headers from verified JWT.", - "properties" : { } + "additionalProperties" : { } }, "kid" : { "type" : "string", @@ -10306,7 +10213,7 @@ "payload" : { "type" : "object", "description" : "Payload from verified JWT", - "properties" : { } + "additionalProperties" : { } }, "valid" : { "type" : "boolean" @@ -10344,7 +10251,7 @@ "filter" : { } }, "description" : "Query dictionary object", - "properties" : { } + "additionalProperties" : { } }, "paginate" : { "$ref" : "#/definitions/KeylistQuery_paginate" @@ -10357,7 +10264,7 @@ "filter" : { "type" : "object", "description" : "Filter for keylist query", - "properties" : { } + "additionalProperties" : { } } } }, @@ -11012,7 +10919,7 @@ "type" : "array", "items" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } } } }, @@ -11138,7 +11045,7 @@ "public_invites" : false }, "description" : "Profile settings dict", - "properties" : { } + "additionalProperties" : { } } } }, @@ -11150,7 +11057,7 @@ }, "proof" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "purpose_result" : { "$ref" : "#/definitions/PurposeResult" @@ -11275,7 +11182,7 @@ "properties" : { "controller" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "error" : { "type" : "string" @@ -11359,64 +11266,6 @@ } } }, - "ReceiveInvitationRequest" : { - "type" : "object", - "properties" : { - "@id" : { - "type" : "string", - "example" : "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "description" : "Message identifier" - }, - "@type" : { - "type" : "string", - "example" : "https://didcomm.org/my-family/1.0/my-message-type", - "description" : "Message type" - }, - "did" : { - "type" : "string", - "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", - "description" : "DID for connection invitation", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" - }, - "imageUrl" : { - "type" : "string", - "format" : "url", - "example" : "http://192.168.56.101/img/logo.jpg", - "description" : "Optional image URL for connection invitation", - "x-nullable" : true - }, - "label" : { - "type" : "string", - "example" : "Bob", - "description" : "Optional label for connection invitation" - }, - "recipientKeys" : { - "type" : "array", - "description" : "List of recipient keys", - "items" : { - "type" : "string", - "example" : "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV", - "description" : "Recipient public key", - "pattern" : "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{43,44}$" - } - }, - "routingKeys" : { - "type" : "array", - "description" : "List of routing keys", - "items" : { - "type" : "string", - "example" : "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV", - "description" : "Routing key", - "pattern" : "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{43,44}$" - } - }, - "serviceEndpoint" : { - "type" : "string", - "example" : "http://192.168.56.101:8020", - "description" : "Service endpoint at which to reach this agent" - } - } - }, "RemoveWalletRequest" : { "type" : "object", "properties" : { @@ -11434,12 +11283,12 @@ "did_document" : { "type" : "object", "description" : "DID Document", - "properties" : { } + "additionalProperties" : { } }, "metadata" : { "type" : "object", "description" : "Resolution metadata", - "properties" : { } + "additionalProperties" : { } } } }, @@ -11513,11 +11362,11 @@ }, "registration_metadata" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "revocation_list_metadata" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "revocation_list_state" : { "$ref" : "#/definitions/RevListState" @@ -11614,11 +11463,11 @@ }, "registration_metadata" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "revocation_registry_definition_metadata" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "revocation_registry_definition_state" : { "$ref" : "#/definitions/RevRegDefState" @@ -11652,7 +11501,7 @@ "publicKeys" : { "type" : "object", "example" : "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV", - "properties" : { } + "additionalProperties" : { } }, "tailsHash" : { "type" : "string", @@ -11720,17 +11569,17 @@ "accum_calculated" : { "type" : "object", "description" : "Calculated accumulator for phantom revocations", - "properties" : { } + "additionalProperties" : { } }, "accum_fixed" : { "type" : "object", "description" : "Applied ledger transaction to fix revocations", - "properties" : { } + "additionalProperties" : { } }, "rev_reg_delta" : { "type" : "object", "description" : "Indy revocation registry delta", - "properties" : { } + "additionalProperties" : { } } } }, @@ -11740,17 +11589,17 @@ "accum_calculated" : { "type" : "object", "description" : "Calculated accumulator for phantom revocations", - "properties" : { } + "additionalProperties" : { } }, "accum_fixed" : { "type" : "object", "description" : "Applied ledger transaction to fix revocations", - "properties" : { } + "additionalProperties" : { } }, "rev_reg_delta" : { "type" : "object", "description" : "Indy revocation registry delta", - "properties" : { } + "additionalProperties" : { } } } }, @@ -11782,9 +11631,6 @@ } } }, - "RevocationAnoncredsModuleResponse" : { - "type" : "object" - }, "RevocationModuleResponse" : { "type" : "object" }, @@ -11955,11 +11801,11 @@ "type" : "string", "example" : "did:peer:WgWxqztrNooG92RXvxSTWv", "description" : "DID of interest", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$|^did:([a-zA-Z0-9_]+)(:[a-zA-Z0-9_.%-]+)?:([a-zA-Z0-9_.%-]+(:[a-zA-Z0-9_.%-]+)*)((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\\/[^#?]*)?([?][^#]*)?(\\#.*)?$$" }, "headers" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "non_sd_list" : { "type" : "array", @@ -11971,7 +11817,7 @@ }, "payload" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "verificationMethod" : { "type" : "string", @@ -12013,7 +11859,7 @@ "headers" : { "type" : "object", "description" : "Headers from verified JWT.", - "properties" : { } + "additionalProperties" : { } }, "kid" : { "type" : "string", @@ -12022,7 +11868,7 @@ "payload" : { "type" : "object", "description" : "Payload from verified JWT", - "properties" : { } + "additionalProperties" : { } }, "valid" : { "type" : "boolean" @@ -12127,11 +11973,11 @@ }, "registration_metadata" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "schema_metadata" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "schema_state" : { "$ref" : "#/definitions/SchemaState" @@ -12301,7 +12147,7 @@ "signed_doc" : { "type" : "object", "description" : "Signed document", - "properties" : { } + "additionalProperties" : { } } } }, @@ -12545,7 +12391,7 @@ }, "mime-type" : "application/json" }, - "properties" : { } + "additionalProperties" : { } } }, "meta_data" : { @@ -12560,7 +12406,7 @@ "other" : "other_value" } ] }, - "properties" : { } + "additionalProperties" : { } }, "signature_request" : { "type" : "array", @@ -12573,7 +12419,7 @@ "signature_type" : "default", "signer_goal_code" : "aries.transaction.endorse" }, - "properties" : { } + "additionalProperties" : { } } }, "signature_response" : { @@ -12586,7 +12432,7 @@ "method" : "add-signature", "signer_goal_code" : "aries.transaction.refuse" }, - "properties" : { } + "additionalProperties" : { } } }, "state" : { @@ -12604,7 +12450,7 @@ "example" : { "expires_time" : "2020-12-13T17:29:06+0000" }, - "properties" : { } + "additionalProperties" : { } }, "trace" : { "type" : "boolean", @@ -12739,7 +12585,7 @@ "public-invites" : false }, "description" : "Agent config key-value pairs", - "properties" : { } + "additionalProperties" : { } } } }, @@ -12749,7 +12595,7 @@ "extra_settings" : { "type" : "object", "description" : "Agent config key-value pairs", - "properties" : { } + "additionalProperties" : { } }, "image_url" : { "type" : "string", @@ -12845,9 +12691,9 @@ }, "issuer_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "Credential issuer DID", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "schema_id" : { "type" : "string", @@ -12857,9 +12703,9 @@ }, "schema_issuer_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "Schema issuer DID", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "schema_name" : { "type" : "string", @@ -12941,7 +12787,7 @@ "credential_request_metadata" : { "type" : "object", "description" : "(Indy) credential request metadata", - "properties" : { } + "additionalProperties" : { } }, "error_msg" : { "type" : "string", @@ -13110,9 +12956,9 @@ }, "issuer_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "Credential issuer DID", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "schema_id" : { "type" : "string", @@ -13122,9 +12968,9 @@ }, "schema_issuer_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "Schema issuer DID", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "schema_name" : { "type" : "string", @@ -13172,9 +13018,9 @@ }, "issuer_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "Credential issuer DID", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "schema_id" : { "type" : "string", @@ -13184,9 +13030,9 @@ }, "schema_issuer_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "Schema issuer DID", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "schema_name" : { "type" : "string", @@ -13720,19 +13566,19 @@ "properties" : { "cred_issue" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "cred_offer" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "cred_proposal" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "cred_request" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } } } }, @@ -13780,7 +13626,7 @@ "cred_request_metadata" : { "type" : "object", "description" : "Credential request metadata for indy holder", - "properties" : { } + "additionalProperties" : { } }, "cred_rev_id" : { "type" : "string", @@ -13919,9 +13765,9 @@ }, "issuer_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "Credential issuer DID", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "schema_id" : { "type" : "string", @@ -13931,9 +13777,9 @@ }, "schema_issuer_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "Schema issuer DID", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "schema_name" : { "type" : "string", @@ -13968,9 +13814,9 @@ }, "issuer_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "Credential issuer DID", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "schema_id" : { "type" : "string", @@ -13980,9 +13826,9 @@ }, "schema_issuer_did" : { "type" : "string", - "example" : "WgWxqztrNooG92RXvxSTWv", + "example" : "did:indy:sovrin:WRfXPg8dantKVubE3HX8pw", "description" : "Schema issuer DID", - "pattern" : "^(did:sov:)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" + "pattern" : "^(did:(sov|indy):)?[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21,22}$" }, "schema_name" : { "type" : "string", @@ -14604,15 +14450,15 @@ "properties" : { "pres" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "pres_proposal" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } }, "pres_request" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } } } }, @@ -14883,7 +14729,7 @@ "cred_value" : { "type" : "object", "description" : "(JSON-serializable) credential value", - "properties" : { } + "additionalProperties" : { } }, "expanded_types" : { "type" : "array", @@ -14947,7 +14793,7 @@ }, "VerifiableCredential" : { "type" : "object", - "required" : [ "@context", "credentialSubject", "issuanceDate", "issuer", "proof", "type" ], + "required" : [ "@context", "credentialSubject", "issuer", "proof", "type" ], "properties" : { "@context" : { "type" : "array", @@ -14993,6 +14839,18 @@ "items" : { "type" : "string" } + }, + "validFrom" : { + "type" : "string", + "example" : "2010-01-01T19:23:24Z", + "description" : "The valid from date", + "pattern" : "^([0-9]{4})-([0-9]{2})-([0-9]{2})([Tt ]([0-9]{2}):([0-9]{2}):([0-9]{2})(\\.[0-9]+)?)?(([Zz]|([+-])([0-9]{2}):([0-9]{2})))?$" + }, + "validUntil" : { + "type" : "string", + "example" : "2010-01-01T19:23:24Z", + "description" : "The valid until date", + "pattern" : "^([0-9]{4})-([0-9]{2})-([0-9]{2})([Tt ]([0-9]{2}):([0-9]{2}):([0-9]{2})(\\.[0-9]+)?)?(([Zz]|([+-])([0-9]{2}):([0-9]{2})))?$" } }, "additionalProperties" : true @@ -15032,7 +14890,7 @@ "type" : "array", "items" : { "type" : "object", - "properties" : { } + "additionalProperties" : { } } } }, @@ -15073,7 +14931,7 @@ "proofValue" : "zHtda8vV7kJQUPfSKiTGSQDhZfhkgtpnVziT7cdEzhu fjPjbeRmysHvizMJEox1eHR7xUGzNUj1V4yaKiLw7UA6E" } ] }, - "properties" : { } + "additionalProperties" : { } } } }, @@ -15234,7 +15092,7 @@ "settings" : { "type" : "object", "description" : "Settings for this wallet.", - "properties" : { } + "additionalProperties" : { } }, "state" : { "type" : "string", diff --git a/pyproject.toml b/pyproject.toml index a0fa0de0a1..98e9625204 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "acapy_agent" -version = "1.2.1" +version = "1.3.0rc0" description = "(ACA-Py) A Cloud Agent Python is a foundation for building decentralized identity applications and services running in non-mobile environments. " authors = [] license = "Apache-2.0" From cbf53d3af1daaf9d12899465015b1de75086b444 Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Mon, 24 Mar 2025 19:28:52 +0200 Subject: [PATCH 46/76] :bug: Fix unchanged endpoint being rewritten to ledger (#3608) Resolves #3607 Signed-off-by: ff137 --- acapy_agent/ledger/indy_vdr.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/acapy_agent/ledger/indy_vdr.py b/acapy_agent/ledger/indy_vdr.py index 77ee86a898..445f94fa39 100644 --- a/acapy_agent/ledger/indy_vdr.py +++ b/acapy_agent/ledger/indy_vdr.py @@ -731,6 +731,7 @@ async def update_endpoint_for_did( endorser_did: DID of the endorser to use for the transaction routing_keys: List of routing keys """ + routing_keys = routing_keys or [] # Ensure list type if None was passed public_info = await self.get_wallet_public_did() if not public_info: raise BadLedgerRequestError( @@ -749,8 +750,13 @@ async def update_endpoint_for_did( existing_routing_keys = ( all_exist_endpoints.get("routingKeys") if all_exist_endpoints else None ) + existing_routing_keys = existing_routing_keys or [] - if exist_endpoint_of_type != endpoint or existing_routing_keys != routing_keys: + endpoint_changed = exist_endpoint_of_type != endpoint + routing_keys_changed = set(existing_routing_keys) != set(routing_keys) + + if endpoint_changed or routing_keys_changed: + LOGGER.info("Endpoint or routing keys have changed, updating endpoint") if self.read_only: raise LedgerError( "Error cannot update endpoint when ledger is in read only mode" From 55e92bd3d4b8f47910886b14980f0169e34f374b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Mar 2025 08:36:37 -0700 Subject: [PATCH 47/76] chore(deps-dev): Bump pre-commit from 4.1.0 to 4.2.0 (#3606) Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 4.1.0 to 4.2.0. - [Release notes](https://github.com/pre-commit/pre-commit/releases) - [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md) - [Commits](https://github.com/pre-commit/pre-commit/compare/v4.1.0...v4.2.0) --- updated-dependencies: - dependency-name: pre-commit dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index f04835a7b6..b6c0311e6d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1928,14 +1928,14 @@ tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "p [[package]] name = "pre-commit" -version = "4.1.0" +version = "4.2.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b"}, - {file = "pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4"}, + {file = "pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd"}, + {file = "pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146"}, ] [package.dependencies] @@ -2973,4 +2973,4 @@ didcommv2 = ["didcomm-messaging"] [metadata] lock-version = "2.1" python-versions = "^3.12" -content-hash = "201e717abe0d645784bc5d17bcec506fbb3f55b79d2f4b5a4d89685192690ec4" +content-hash = "d1bf934d30d520d31137e9b3d2c4ef69206c9ff2a74a2c1268c15cccb48d7783" diff --git a/pyproject.toml b/pyproject.toml index 98e9625204..8c9766d1a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,7 +72,7 @@ canonicaljson = "^2.0.0" # Sync with version in .pre-commit-config.yaml and .github/workflows/format.yml ruff = "~0.11.0" -pre-commit = "~4.1.0" +pre-commit = ">=4.1,<4.3" pydevd = "~3.3.0" From fb1f6b44768f23a100002b214b6e9fd173b3dcc2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Mar 2025 08:47:14 -0700 Subject: [PATCH 48/76] chore(deps): Bump tj-actions/changed-files in the all-actions group (#3610) Bumps the all-actions group with 1 update: [tj-actions/changed-files](https://github.com/tj-actions/changed-files). Updates `tj-actions/changed-files` from 46.0.1 to 46.0.3 - [Release notes](https://github.com/tj-actions/changed-files/releases) - [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md) - [Commits](https://github.com/tj-actions/changed-files/compare/v46.0.1...v46.0.3) --- updated-dependencies: - dependency-name: tj-actions/changed-files dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- .github/workflows/bdd-integration-tests.yml | 2 +- .github/workflows/bdd-interop-tests.yml | 2 +- .github/workflows/scenario-integration-tests.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/bdd-integration-tests.yml b/.github/workflows/bdd-integration-tests.yml index 5bb7bba4ad..6960f9e208 100644 --- a/.github/workflows/bdd-integration-tests.yml +++ b/.github/workflows/bdd-integration-tests.yml @@ -31,7 +31,7 @@ jobs: fetch-depth: 0 - name: Check changed files id: check-changed-files - uses: tj-actions/changed-files@v46.0.1 + uses: tj-actions/changed-files@v46.0.3 with: files_yaml: | src: diff --git a/.github/workflows/bdd-interop-tests.yml b/.github/workflows/bdd-interop-tests.yml index 0a979fb02b..b24d6530f2 100644 --- a/.github/workflows/bdd-interop-tests.yml +++ b/.github/workflows/bdd-interop-tests.yml @@ -31,7 +31,7 @@ jobs: fetch-depth: 0 - name: Check changed files id: check-changed-files - uses: tj-actions/changed-files@v46.0.1 + uses: tj-actions/changed-files@v46.0.3 with: files_yaml: | src: diff --git a/.github/workflows/scenario-integration-tests.yml b/.github/workflows/scenario-integration-tests.yml index ff3616e030..6406bd20d3 100644 --- a/.github/workflows/scenario-integration-tests.yml +++ b/.github/workflows/scenario-integration-tests.yml @@ -29,7 +29,7 @@ jobs: fetch-depth: 0 - name: Check changed files id: check-changed-files - uses: tj-actions/changed-files@v46.0.1 + uses: tj-actions/changed-files@v46.0.3 with: files_yaml: | scenarios: "scenarios/**/*" From c76dd09cc1c01a850efa98524d5f3b4847823b56 Mon Sep 17 00:00:00 2001 From: Yuki I <42908250+MonolithicMonk@users.noreply.github.com> Date: Tue, 25 Mar 2025 10:58:31 -0500 Subject: [PATCH 49/76] fix(ledger): correct response format for /ledger/get-write-ledgers endpoint (#3613) - Wrap response in key to match OpenAPI schema - Add unit tests for single/multi-ledger scenarios - Validate schema compliance in tests Fixes #3612 Signed-off-by: Yuki I Co-authored-by: Yuki I Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- acapy_agent/ledger/routes.py | 4 +- acapy_agent/ledger/tests/test_routes.py | 58 +++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/acapy_agent/ledger/routes.py b/acapy_agent/ledger/routes.py index fee5e15261..c84638ee9e 100644 --- a/acapy_agent/ledger/routes.py +++ b/acapy_agent/ledger/routes.py @@ -711,9 +711,9 @@ async def get_write_ledgers(request: web.BaseRequest): async with context.profile.session() as session: multiledger_mgr = session.inject_or(BaseMultipleLedgerManager) if not multiledger_mgr: - return web.json_response(["default"]) + return web.json_response({"write_ledgers": ["default"]}) available_write_ledgers = await multiledger_mgr.get_write_ledgers() - return web.json_response(available_write_ledgers) + return web.json_response({"write_ledgers": available_write_ledgers}) @docs(tags=["ledger"], summary="Fetch the current write ledger") diff --git a/acapy_agent/ledger/tests/test_routes.py b/acapy_agent/ledger/tests/test_routes.py index 70e1092b56..03532fd3a3 100644 --- a/acapy_agent/ledger/tests/test_routes.py +++ b/acapy_agent/ledger/tests/test_routes.py @@ -1,3 +1,4 @@ +import json from typing import Optional from unittest import IsolatedAsyncioTestCase @@ -8,6 +9,8 @@ from ...ledger.multiple_ledger.ledger_requests_executor import ( IndyLedgerRequestsExecutor, ) +from ...ledger.multiple_ledger.ledger_config_schema import ConfigurableWriteLedgersSchema + from ...multitenant.base import BaseMultitenantManager from ...multitenant.manager import MultitenantManager from ...tests import mock @@ -865,3 +868,58 @@ async def test_get_ledger_config(self): async def test_get_ledger_config_x(self): with self.assertRaises(test_module.web.HTTPForbidden): await test_module.get_ledger_config(self.request) + + # Multiple Ledgers Configured + async def test_get_write_ledgers_multiple(self): + # Mock the multiple ledger manager + mock_manager = mock.MagicMock(BaseMultipleLedgerManager) + mock_manager.get_write_ledgers = mock.CoroutineMock( + return_value=["ledger1", "ledger2", "ledger3"] + ) + self.profile.context.injector.bind_instance( + BaseMultipleLedgerManager, mock_manager + ) + + with mock.patch.object( + test_module.web, "json_response", mock.Mock() + ) as json_response: + result = await test_module.get_write_ledgers(self.request) + + # Assert the response matches the expected structure + json_response.assert_called_once_with( + {"write_ledgers": ["ledger1", "ledger2", "ledger3"]} + ) + assert result is json_response.return_value + + # Single Ledger (No Multi-Ledger Manager) + async def test_get_write_ledgers_single(self): + # Ensure no multi-ledger manager is bound + self.profile.context.injector.clear_binding(BaseMultipleLedgerManager) + + result = await test_module.get_write_ledgers(self.request) + + # Extract the JSON body from the response + response_body = result.text + response_body = json.loads(response_body) + + # Assert the response is correct + self.assertEqual(response_body, {"write_ledgers": ["default"]}) + + # Schema Validation + async def test_get_write_ledgers_schema(self): + # Mock the multiple ledger manager + mock_manager = mock.MagicMock(BaseMultipleLedgerManager) + mock_manager.get_write_ledgers = mock.CoroutineMock( + return_value=["ledger1", "ledger2"] + ) + self.profile.context.injector.bind_instance( + BaseMultipleLedgerManager, mock_manager + ) + + response = await test_module.get_write_ledgers(self.request) + + # Validate against the schema + schema = ConfigurableWriteLedgersSchema() + data = json.loads(response.body) + validated = schema.validate(data) + assert validated == {} From 96ea8e0fc5157112119b6606e46981d36ca12a7f Mon Sep 17 00:00:00 2001 From: Ian Costanzo Date: Tue, 25 Mar 2025 10:11:02 -0700 Subject: [PATCH 50/76] Fix demo implementation of vc_di cred issue (#3609) * Fix demo implementation of vc_di cred issue Signed-off-by: Ian Costanzo * Oops formatting issue Signed-off-by: Ian Costanzo * Oops formatting issue Signed-off-by: Ian Costanzo --------- Signed-off-by: Ian Costanzo --- .../issue_credential/v2_0/formats/vc_di/handler.py | 6 +++++- demo/runners/faber.py | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/handler.py b/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/handler.py index 7ab50cf9ae..3412cc93b8 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/handler.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/handler.py @@ -376,8 +376,12 @@ async def _create(): cred_request_metadata=cred_req_result["metadata"], ) + if "prover_did" in cred_req_result["request"]: + entropy = cred_req_result["request"]["prover_did"] + else: + entropy = cred_req_result["request"]["entropy"] anoncreds_link_secret_instance = AnoncredsLinkSecretRequest( - entropy=cred_req_result["request"]["prover_did"], + entropy=entropy, cred_def_id=cred_req_result["request"]["cred_def_id"], blinded_ms=cred_req_result["request"]["blinded_ms"], blinded_ms_correctness_proof=cred_req_result["request"][ diff --git a/demo/runners/faber.py b/demo/runners/faber.py index 5e1322d974..57ea76c62e 100644 --- a/demo/runners/faber.py +++ b/demo/runners/faber.py @@ -128,10 +128,10 @@ def generate_credential_offer(self, aip, cred_type, cred_def_id, exchange_tracin for (n, v) in self.cred_attrs[cred_def_id].items() ], } - if cred_type == CRED_FORMAT_ANONCREDS: - _filter = {"anoncreds": {"cred_def_id": cred_def_id}} - else: + if cred_type == CRED_FORMAT_INDY: _filter = {"indy": {"cred_def_id": cred_def_id}} + else: + _filter = {"anoncreds": {"cred_def_id": cred_def_id}} offer_request = { "connection_id": self.connection_id, "comment": f"Offer on cred def id {cred_def_id}", From ddc70aeada186a92bbf61bc974fbee031e0a35c9 Mon Sep 17 00:00:00 2001 From: David Chaiken Date: Tue, 25 Mar 2025 12:39:25 -0700 Subject: [PATCH 51/76] feat(demo): remove broken aip 10 and fix aip 20 (#3611) * demo: fix connectionless proof Signed-off-by: David Chaiken * demo: send correct endpoint for connectionless proof requests Signed-off-by: David Chaiken * feat(demo): update documentation removing aip 10 Signed-off-by: David Chaiken --------- Signed-off-by: David Chaiken Co-authored-by: Ian Costanzo Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- demo/runners/support/agent.py | 6 +++--- docs/demo/AliceGetsAPhone.md | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/demo/runners/support/agent.py b/demo/runners/support/agent.py index 5d1e10ccd6..fd77ae38b3 100644 --- a/demo/runners/support/agent.py +++ b/demo/runners/support/agent.py @@ -1004,17 +1004,17 @@ async def service_decorator(self): decorator = { "recipientKeys": [agent_public_did["result"]["verkey"]], # "routingKeys": [agent_public_did["result"]["verkey"]], - "serviceEndpoint": agent_endpoint["endpoint"], + "serviceEndpoint": agent_endpoint["endpoint"] or self.endpoint, } return decorator async def _send_connectionless_proof_req(self, request: ClientRequest): pres_req_id = request.match_info["pres_req_id"] - url = "/present-proof/records/" + pres_req_id + url = "/present-proof-2.0/records/" + pres_req_id proof_exch = await self.admin_GET(url) if not proof_exch: return web.Response(status=404) - proof_reg_txn = proof_exch["presentation_request_dict"] + proof_reg_txn = proof_exch["pres_request"] proof_reg_txn["~service"] = await self.service_decorator() if request.headers.get("Accept") == "application/json": return web.json_response(proof_reg_txn) diff --git a/docs/demo/AliceGetsAPhone.md b/docs/demo/AliceGetsAPhone.md index 5fd8f6de1d..63045fd7b8 100644 --- a/docs/demo/AliceGetsAPhone.md +++ b/docs/demo/AliceGetsAPhone.md @@ -142,11 +142,9 @@ If you are running in a _local bash shell_, navigate to the `demo` directory in your fork/clone of the ACA-Py repository and run: ```bash -TAILS_NETWORK=docker_tails-server LEDGER_URL=http://test.bcovrin.vonx.io ./run_demo faber --aip 10 --revocation --events +TAILS_NETWORK=docker_tails-server LEDGER_URL=http://test.bcovrin.vonx.io ./run_demo faber --revocation --events ``` -(Note that we have to start faber with `--aip 10` for compatibility with mobile clients.) - The `TAILS_NETWORK` parameter lets the demo script know how to connect to the tails server (which should be running in a separate shell on the same machine). #### Running in Play with Docker? @@ -155,7 +153,7 @@ If you are running in _Play with Docker_, navigate to the `demo` folder in the clone of ACA-Py and run the following: ```bash -PUBLIC_TAILS_URL=https://c4f7fbb85911.ngrok.io LEDGER_URL=http://test.bcovrin.vonx.io ./run_demo faber --aip 10 --revocation --events +PUBLIC_TAILS_URL=https://c4f7fbb85911.ngrok.io LEDGER_URL=http://test.bcovrin.vonx.io ./run_demo faber --revocation --events ``` The `PUBLIC_TAILS_URL` parameter lets the demo script know how to connect to the tails server. This can be running in another PWD session, or even on your local machine - the ngrok endpoint is public and will map to the correct location. From 1527027cae8dfe8ea16153a34e4ba337a7e2c7f7 Mon Sep 17 00:00:00 2001 From: Ivan Polchenko <2119240+i5okie@users.noreply.github.com> Date: Tue, 25 Mar 2025 14:08:52 -0700 Subject: [PATCH 52/76] Create Acapy Helm Chart (#3599) * Create Acapy Helm chart Signed-off-by: Ivan P <2119240+i5okie@users.noreply.github.com> * Update templates, values, create readme Signed-off-by: Ivan P <2119240+i5okie@users.noreply.github.com> * remove ledger from default values Signed-off-by: Ivan P <2119240+i5okie@users.noreply.github.com> * Update Readme Signed-off-by: Ivan P <2119240+i5okie@users.noreply.github.com> * Update acapy version Signed-off-by: Ivan P <2119240+i5okie@users.noreply.github.com> * Cleanup helpers file Signed-off-by: Ivan P <2119240+i5okie@users.noreply.github.com> * Implement websockets flag Signed-off-by: Ivan P <2119240+i5okie@users.noreply.github.com> * Update Readme Signed-off-by: Ivan P <2119240+i5okie@users.noreply.github.com> * Addressing comments Signed-off-by: Ivan P <2119240+i5okie@users.noreply.github.com> --------- Signed-off-by: Ivan P <2119240+i5okie@users.noreply.github.com> Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- charts/acapy/.helmignore | 23 + charts/acapy/Chart.lock | 9 + charts/acapy/Chart.yaml | 18 + charts/acapy/README.md | 314 +++++++ charts/acapy/charts/common-2.27.0.tgz | Bin 0 -> 15622 bytes charts/acapy/charts/postgresql-15.5.38.tgz | Bin 0 -> 75781 bytes charts/acapy/templates/NOTES.txt | 27 + charts/acapy/templates/_helpers.tpl | 155 ++++ charts/acapy/templates/api-secret.yaml | 21 + charts/acapy/templates/configmap.yaml | 21 + charts/acapy/templates/deployment.yaml | 210 +++++ charts/acapy/templates/extra-list.yaml | 4 + charts/acapy/templates/hpa.yaml | 52 ++ charts/acapy/templates/ingress-admin.yaml | 57 ++ charts/acapy/templates/ingress-agent.yaml | 57 ++ charts/acapy/templates/networkpolicy.yaml | 56 ++ charts/acapy/templates/seed-secret.yaml | 15 + charts/acapy/templates/service.yaml | 66 ++ charts/acapy/templates/serviceaccount.yaml | 10 + charts/acapy/templates/tails-pvc.yaml | 23 + charts/acapy/values.yaml | 941 +++++++++++++++++++++ 21 files changed, 2079 insertions(+) create mode 100644 charts/acapy/.helmignore create mode 100644 charts/acapy/Chart.lock create mode 100644 charts/acapy/Chart.yaml create mode 100644 charts/acapy/README.md create mode 100644 charts/acapy/charts/common-2.27.0.tgz create mode 100644 charts/acapy/charts/postgresql-15.5.38.tgz create mode 100644 charts/acapy/templates/NOTES.txt create mode 100644 charts/acapy/templates/_helpers.tpl create mode 100644 charts/acapy/templates/api-secret.yaml create mode 100644 charts/acapy/templates/configmap.yaml create mode 100644 charts/acapy/templates/deployment.yaml create mode 100644 charts/acapy/templates/extra-list.yaml create mode 100644 charts/acapy/templates/hpa.yaml create mode 100644 charts/acapy/templates/ingress-admin.yaml create mode 100644 charts/acapy/templates/ingress-agent.yaml create mode 100644 charts/acapy/templates/networkpolicy.yaml create mode 100644 charts/acapy/templates/seed-secret.yaml create mode 100644 charts/acapy/templates/service.yaml create mode 100644 charts/acapy/templates/serviceaccount.yaml create mode 100644 charts/acapy/templates/tails-pvc.yaml create mode 100644 charts/acapy/values.yaml diff --git a/charts/acapy/.helmignore b/charts/acapy/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/acapy/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/acapy/Chart.lock b/charts/acapy/Chart.lock new file mode 100644 index 0000000000..19065c717a --- /dev/null +++ b/charts/acapy/Chart.lock @@ -0,0 +1,9 @@ +dependencies: +- name: postgresql + repository: https://charts.bitnami.com/bitnami/ + version: 15.5.38 +- name: common + repository: https://charts.bitnami.com/bitnami/ + version: 2.27.0 +digest: sha256:b97fd206aee47f3869935fdbe062eded88b9c429a411b32335e4effa99318c36 +generated: "2025-03-06T09:40:05.890168-08:00" diff --git a/charts/acapy/Chart.yaml b/charts/acapy/Chart.yaml new file mode 100644 index 0000000000..4357419959 --- /dev/null +++ b/charts/acapy/Chart.yaml @@ -0,0 +1,18 @@ +apiVersion: v2 +name: acapy +description: A Helm chart for ACA-Py - A Cloud Agent - Python +type: application + +version: 0.1.0 +appVersion: "1.2.4" + +dependencies: + - name: postgresql + version: 15.5.38 + repository: https://charts.bitnami.com/bitnami/ + condition: postgresql.enabled + - name: common + repository: https://charts.bitnami.com/bitnami/ + tags: + - bitnami-common + version: 2.x.x diff --git a/charts/acapy/README.md b/charts/acapy/README.md new file mode 100644 index 0000000000..d15a6e22e6 --- /dev/null +++ b/charts/acapy/README.md @@ -0,0 +1,314 @@ +# AcaPy + +![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.2.2](https://img.shields.io/badge/AppVersion-1.2.2-informational?style=flat-square) + +A Helm chart to deploy A Cloud Agent - Python. + +## Prerequisites + +- Kubernetes 1.19+ +- Helm 3.2.0+ +- PV provisioner support in the underlying infrastructure + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```console +helm repo add acapy https://openwallet-foundation.github.io/acapy/ +helm install my-release acapy/acapy +``` + +The command deploys AcaPY agent, along with PostgreSQL on the Kubernetes cluster in the default configuration. The [Parameters](#parameters) section lists the parameters that can be configured during installation. + +> **Tip**: List all releases using `helm list` + + +## Parameters + +### Common parameters + +| Name | Description | Value | +| --------------------- | ----------------------------------------------------------------------------------------------------- | ----------------------- | +| `nameOverride` | String to partially override fullname include (will maintain the release name) | `""` | +| `fullnameOverride` | String to fully override fullname template | `""` | +| `namespaceOverride` | String to fully override common.names.namespace | `""` | +| `kubeVersion` | Force target Kubernetes version (using Helm capabilities if not set) | `""` | +| `commonLabels` | Labels to add to all deployed objects | `{}` | +| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | +| `replicaCount` | Number of AcaPy pods | `1` | +| `updateStrategy.type` | Set up update strategy for AcaPy installation. | `RollingUpdate` | +| `image.registry` | AcaPy image registry | `REGISTRY_NAME` | +| `image.repository` | AcaPy Image name | `REPOSITORY_NAME/AcaPy` | +| `image.digest` | AcaPy image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `image.pullPolicy` | AcaPy image pull policy | `IfNotPresent` | +| `image.pullSecrets` | Specify docker-registry secret names as an array | `[]` | + +### Configuration files + +Configuration file is mounted as is into the container. See the AcaPy documentation for details. +Note: Secure values of the configuration are passed via equivalent environment variables from secrets. + +| Name | Description | Value | +| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | +| `argfile.yml.admin-insecure-mode` | Run the admin web server in insecure mode. DO NOT USE FOR PRODUCTION DEPLOYMENTS. The admin server will be publicly available to anyone who has access to the interface. An auto-generated admin API Key is supplied via `ACAPY-ADMIN-API-KEY`. | `false` | +| `argfile.yml.auto-accept-invites` | Automatically accept invites without firing a webhook event or waiting for an admin request. Default: false. | `true` | +| `argfile.yml.auto-accept-requests` | Automatically accept connection requests without firing a webhook event or waiting for an admin request. Default: false. | `true` | +| `argfile.yml.auto-create-revocation-transactions` | For Authors, specify whether to automatically create transactions for a cred def's revocation registry. (If not specified, the controller must invoke the endpoints required to create the revocation registry and assign to the cred def.) | `false` | +| `argfile.yml.auto-promote-author-did` | For authors, specify whether to automatically promote a DID to the wallet public DID after writing to the ledger.`` | `true` | +| `argfile.yml.auto-ping-connection` | Automatically send a trust ping immediately after a connection response is accepted. Some agents require this before marking a connection as 'active'. Default: false. | `true` | +| `argfile.yml.auto-provision` | If the requested profile does not exist, initialize it with the given parameters. | `true` | +| `argfile.yml.auto-request-endorsement` | For Authors, specify whether to automatically request endorsement for all transactions. (If not specified, the controller must invoke the request endorse operation for each transaction.) | `false` | +| `argfile.yml.auto-respond-credential-offer` | Automatically respond to Indy credential offers with a credential request. Default: false | `true` | +| `argfile.yml.auto-respond-credential-proposal` | Auto-respond to credential proposals with corresponding credential offers. | `false` | +| `argfile.yml.auto-respond-credential-request` | Auto-respond to credential requests with corresponding credentials. | `false` | +| `argfile.yml.auto-respond-presentation-proposal` | Auto-respond to presentation proposals with corresponding presentation requests. | `true` | +| `argfile.yml.auto-respond-presentation-request` | Automatically respond to Indy presentation requests with a constructed presentation if a corresponding credential can be retrieved for every referent in the presentation request. Default: false. | `false` | +| `argfile.yml.auto-store-credential` | Automatically store an issued credential upon receipt. Default: false. | `true` | +| `argfile.yml.auto-verify-presentation` | Automatically verify a presentation when it is received. Default: false. | `false` | +| `argfile.yml.auto-write-transactions` | For Authors, specify whether to automatically write any endorsed transactions. (If not specified, the controller must invoke the write transaction operation for each transaction.) | `false` | +| `argfile.yml.emit-new-didcomm-mime-type` | Send packed agent messages with the DIDComm MIME type as of RFC 0044; i.e., 'application/didcomm-envelope-enc' instead of 'application/ssi-agent-wire'. | `true` | +| `argfile.yml.emit-new-didcomm-prefix` | Emit protocol messages with new DIDComm prefix; i.e., 'https://didcomm.org/' instead of (default) prefix 'did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/'. | `true` | +| `argfile.yml.endorser-alias` | For transaction Authors, specify the alias of the Endorser connection that will be used to endorse transactions. | `endorser` | +| `argfile.yml.endorser-protocol-role` | Specify the role ('author' or 'endorser') which this agent will participate. Authors will request transaction endorsement from an Endorser. Endorsers will endorse transactions from Authors, and may write their own transactions to the ledger. If no role (or 'none') is specified then the endorsement protocol will not be used and this agent will write transactions to the ledger directly. | `author` | +| `argfile.yml.auto-respond-messages` | Automatically respond to basic messages indicating the message was received. Default: false. | `true` | +| `argfile.yml.auto-verify-presentation` | Automatically verify a presentation when it is received. Default: false. | `false` | +| `argfile.yml.genesis-transactions-list` | Load YAML configuration for connecting to multiple HyperLedger Indy ledgers. | `/tmp/ledgers.yml` | +| `argfile.yml.log-level` | Specifies a custom logging level as one of: ('debug', 'info', 'warning', 'error', 'critical') | `info` | +| `argfile.yml.monitor-ping` | Send a webhook when a ping is sent or received. | `false` | +| `argfile.yml.multitenant-admin` | Specify whether to enable the multitenant admin api. | `false` | +| `argfile.yml.multitenant` | Enable multitenant mode. | `false` | +| `argfile.yml.notify-revocation` | Specifies that aca-py will notify credential recipients when revoking a credential it issued. | `false` | +| `argfile.yml.preserve-exchange-records` | Keep credential exchange records after exchange has completed. | `true` | +| `argfile.yml.requests-through-public-did` | Must be set to true when using "implicit" invitations. | `false` | +| `argfile.yml.public-invites` | Send invitations out using the public DID for the agent, and receive connection requests solicited by invitations which use the public DID. Default: false. | `false` | +| `argfile.yml.read-only-ledger` | Sets ledger to read-only to prevent updates. Default: false. | `true` | +| `argfile.yml.wallet-local-did` | If this parameter is set, provisions the wallet with a local DID from the '--seed' parameter, instead of a public DID to use with a Hyperledger Indy ledger. Default: false. | `true` | +| `argfile.yml.wallet-name` | Specifies the wallet name to be used by the agent. This is useful if your deployment has multiple wallets. | `askar-wallet` | +| `argfile.yml.wallet-storage-type` | Specifies the type of Indy wallet backend to use. Supported internal storage types are 'basic' (memory), 'default' (sqlite), and 'postgres_storage'. The default, if not specified, is 'default'. | `postgres_storage` | +| `argfile.yml.wallet-type` | Specifies the type of Indy wallet provider to use. Supported internal storage types are 'basic' (memory) and 'indy'. The default (if not specified) is 'basic'. | `askar` | +| `argfile.yml.webhook-url` | Send webhooks containing internal state changes to the specified URL. Optional API key to be passed in the request body can be appended using a hash separator [#]. This is useful for a controller to monitor agent events and respond to those events using the admin API. If not specified, webhooks are not published by the agent. | `{{ include "acapy.host" . }}` | +| `ledgers.yml` | | `{}` | +| `plugin-config.yml` | Plugin configuration file | `{}` | +| `websockets.enabled` | Enable or disable the websocket transport for the agent. | `false` | + +### Wallet Storage configuration + +Specifies the storage configuration to use for the wallet. +This is required if you are for using 'postgres_storage' wallet 'storage type. +For example, '{"url":"localhost:5432", "wallet_scheme":"MultiWalletSingleTable"}'. +This configuration maps to the indy sdk postgres plugin (PostgresConfig). + +| Name | Description | Value | +| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | +| `walletStorageConfig.json` | Raw json, overrides all other values including postgres subchart values. e.g.: '{"url":"localhost:5432", "max_connections":"10", "wallet_scheme":"DatabasePerWallet"}' | `""` | +| `walletStorageConfig.url` | Database url. Overrides all other values including postgres subchart values. | `""` | +| `walletStorageConfig.max_connections` | Client max connections, defaults to 10. | `10` | +| `walletStorageConfig.wallet_scheme` | Wallet scheme. | `DatabasePerWallet` | + +### Wallet Storage Credentials + +Specifies the storage credentials to use for the wallet. +This is required if you are for using 'postgres_storage' wallet 'storage type. +For example, '{"account":"postgres","password":"mysecretpassword","admin_account":"postgres","admin_password":"mysecretpassword"}'. +This configuration maps to the indy sdk postgres plugin (PostgresCredential). +NOTE: admin_user must have the CREATEDB role or else initialization will fail. + +| Name | Description | Value | +| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------- | +| `walletStorageCredentials.json` | Raw json with database credentials. Overrides all other values including postgres subchart values. e.g.: '{"account":"postgres","password":"mysecretpassword","admin_account":"postgres","admin_password":"mysecretpassword"}' | `""` | +| `walletStorageCredentials.account` | Database account name. | `acapy` | +| `walletStorageCredentials.admin_account` | Database account with CREATEDB role used to create additional databases per wallet. | `postgres` | +| `walletStorageCredentials.admin_password` | Database password for admin account. | `""` | +| `walletStorageCredentials.existingSecret` | Name of an existing secret containing 'database-user', 'database-password', 'admin-password' keys. | `""` | +| `walletStorageCredentials.secretKeys.adminPasswordKey` | Key in existing secret containing admin password. | `postgres-password` | +| `walletStorageCredentials.secretKeys.userPasswordKey` | Key in existing secret containing password . | `password` | + +### Persistence + +| Name | Description | Value | +| --------------------------- | ------------------------------------ | ------------------- | +| `persistence.enabled` | Enable persistence using PVC | `true` | +| `persistence.existingClaim` | Name of an existing PVC to use | `""` | +| `persistence.storageClass` | PVC Storage Class for Tails volume | `""` | +| `persistence.accessModes` | PVC Access Mode for Tails volume | `["ReadWriteMany"]` | +| `persistence.size` | PVC Storage Request for Tails volume | `1Gi` | +| `persistence.annotations` | Persistent Volume Claim annotations | `{}` | + +### Service and Ports + +| Name | Description | Value | +| ---------------------------------- | ---------------------------------------------------------------- | ----------- | +| `service.type` | AcaPy service type | `ClusterIP` | +| `service.ports.http` | AcaPy service HTTP port | `8021` | +| `service.ports.admin` | AcaPy service admin port | `8022` | +| `service.ports.ws` | AcaPy service websockets port | `8023` | +| `service.nodePorts.http` | Node port for HTTP | `""` | +| `service.nodePorts.admin` | Node port for admin | `""` | +| `service.nodePorts.ws` | Node port for websockets | `""` | +| `service.sessionAffinity` | Control where client requests go, to the same pod or round-robin | `None` | +| `service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | +| `service.clusterIP` | AcaPy service Cluster IP | `""` | +| `service.loadBalancerIP` | AcaPy service Load Balancer IP | `""` | +| `service.loadBalancerSourceRanges` | AcaPy service Load Balancer sources | `[]` | +| `service.externalTrafficPolicy` | AcaPy service external traffic policy | `Cluster` | +| `service.annotations` | Additional custom annotations for AcaPy service | `{}` | +| `service.extraPorts` | Extra port to expose on AcaPy service | `[]` | + +### Network Policy + +| Name | Description | Value | +| --------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------ | +| `networkPolicy.enabled` | Specifies whether a NetworkPolicy should be created | `true` | +| `networkPolicy.allowExternal` | Don't require server label for connections | `true` | +| `networkPolicy.allowExternalEgress` | Allow the pod to access any range of port and all destinations. | `true` | +| `networkPolicy.addExternalClientAccess` | Allow access from pods with client label set to "true". Ignored if `networkPolicy.allowExternal` is true. | `true` | +| `networkPolicy.extraIngress` | Add extra ingress rules to the NetworkPolicy | `[]` | +| `networkPolicy.extraEgress` | Add extra ingress rules to the NetworkPolicy | `[]` | +| `networkPolicy.ingressPodMatchLabels` | Labels to match to allow traffic from other pods. Ignored if `networkPolicy.allowExternal` is true. | `{}` | +| `networkPolicy.ingressNSMatchLabels` | Labels to match to allow traffic from other namespaces. Ignored if `networkPolicy.allowExternal` is true. | `{}` | +| `networkPolicy.ingressNSPodMatchLabels` | Pod labels to match to allow traffic from other namespaces. Ignored if `networkPolicy.allowExternal` is true. | `{}` | + +### Ingress and Endpoint configuration + +| Name | Description | Value | +| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | +| `agentUrl` | must be set if ingress is not enabled | `""` | +| `adminUrl` | must be set if ingress is not enabled | `""` | +| `ingress.agent.enabled` | Set to true to enable ingress record generation | `false` | +| `ingress.agent.pathType` | Ingress Path type | `ImplementationSpecific` | +| `ingress.agent.apiVersion` | Override API Version (automatically detected if not set) | `""` | +| `ingress.agent.hostname` | When the ingress is enabled, a host pointing to this will be created | `acapy.local` | +| `ingress.agent.path` | Default path for the ingress resource | `/` | +| `ingress.agent.annotations` | Additional annotations for the Ingress resource. To enable certificate autogeneration, place here your cert-manager annotations. | `{}` | +| `ingress.agent.tls` | Enable TLS configuration for the hostname defined at ingress.hostname parameter | `false` | +| `ingress.agent.extraHosts` | The list of additional hostnames to be covered with this ingress record. | `[]` | +| `ingress.agent.extraPaths` | Any additional arbitrary paths that may need to be added to the ingress under the main host. | `[]` | +| `ingress.agent.extraTls` | The tls configuration for additional hostnames to be covered with this ingress record. | `[]` | +| `ingress.agent.secrets` | If you're providing your own certificates, please use this to add the certificates as secrets | `[]` | +| `ingress.agent.secrets` | It is also possible to create and manage the certificates outside of this helm chart | `[]` | +| `ingress.agent.selfSigned` | Create a TLS secret for this ingress record using self-signed certificates generated by Helm | `false` | +| `ingress.agent.ingressClassName` | IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+) | `""` | +| `ingress.agent.extraRules` | Additional rules to be covered with this ingress record | `[]` | +| `ingress.admin.enabled` | Set to true to enable ingress record generation | `false` | +| `ingress.admin.pathType` | Ingress Path type | `ImplementationSpecific` | +| `ingress.admin.apiVersion` | Override API Version (automatically detected if not set) | `""` | +| `ingress.admin.hostname` | When the ingress is enabled, a host pointing to this will be created | `admin.acapy.local` | +| `ingress.admin.path` | Default path for the ingress resource | `/` | +| `ingress.admin.annotations` | Additional annotations for the Ingress resource. To enable certificate autogeneration, place here your cert-manager annotations. | `{}` | +| `ingress.admin.tls` | Enable TLS configuration for the hostname defined at ingress.hostname parameter | `false` | +| `ingress.admin.extraHosts` | The list of additional hostnames to be covered with this ingress record. | `[]` | +| `ingress.admin.extraPaths` | Any additional arbitrary paths that may need to be added to the ingress under the main host. | `[]` | +| `ingress.admin.extraTls` | The tls configuration for additional hostnames to be covered with this ingress record. | `[]` | +| `ingress.admin.secrets` | If you're providing your own certificates, please use this to add the certificates as secrets | `[]` | +| `ingress.admin.secrets` | It is also possible to create and manage the certificates outside of this helm chart | `[]` | +| `ingress.admin.selfSigned` | Create a TLS secret for this ingress record using self-signed certificates generated by Helm | `false` | +| `ingress.admin.ingressClassName` | IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+) | `""` | +| `ingress.admin.extraRules` | Additional rules to be covered with this ingress record | `[]` | + +### Deployment parameters + +| Name | Description | Value | +| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | +| `resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if resources is set (resources is recommended for production). | `none` | +| `resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | +| `livenessProbe.enabled` | Enable livenessProbe | `true` | +| `livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `30` | +| `livenessProbe.periodSeconds` | Period seconds for livenessProbe | `20` | +| `livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `10` | +| `livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `6` | +| `livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | +| `livenessProbe.httpGet.path` | Request path for livenessProbe | `/status/live` | +| `livenessProbe.httpGet.port` | Port for livenessProbe | `admin` | +| `readinessProbe.enabled` | Enable readinessProbe | `true` | +| `readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `5` | +| `readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | +| `readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `5` | +| `readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `6` | +| `readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | +| `readinessProbe.httpGet.path` | Request path for readinessProbe | `/status/ready` | +| `readinessProbe.httpGet.port` | Port for readinessProbe | `admin` | +| `initContainers` | Add additional init containers for the hidden node pod(s) | `[]` | +| `extraArgs` | Array containing extra command line arguments to configure aca-py | `[]` | +| `extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars | `""` | +| `extraEnvVarsSecret` | Name of existing Secret containing extra env vars | `""` | +| `extraEnvVars` | Array containing extra env vars to configure AcaPy | `[]` | +| `nodeAffinityPreset.type` | Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `nodeAffinityPreset.key` | Node label key to match Ignored if `affinity` is set. | `""` | +| `nodeAffinityPreset.values` | Node label values to match. Ignored if `affinity` is set. | `[]` | +| `affinity` | Affinity for pod assignment | `{}` | +| `podAffinityPreset` | Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `nodeSelector` | Node labels for pod assignment | `{}` | +| `tolerations` | Tolerations for pod assignment | `[]` | +| `topologySpreadConstraints` | Topology spread constraints rely on node labels to identify the topology domain(s) that each Node is in | `[]` | +| `podLabels` | Pod labels | `{}` | +| `podAnnotations` | Pod annotations | `{}` | +| `extraVolumes` | Array of extra volumes to be added to the deployment (evaluated as template). Requires setting `extraVolumeMounts` | `[]` | +| `extraVolumeMounts` | Array of extra volume mounts to be added to the container (evaluated as template). Normally used with `extraVolumes`. | `[]` | +| `extraDeploy` | Array of extra objects to deploy with the release | `[]` | + +### PostgreSQL Parameters + + +### Autoscaling + +| Name | Description | Value | +| ----------------------------------------------------------- | -------------------------------------------------------------------------------------------- | ------- | +| `autoscaling.enabled` | Enable Horizontal POD autoscaling for AcaPy | `false` | +| `autoscaling.minReplicas` | Minimum number of AcaPy replicas | `1` | +| `autoscaling.maxReplicas` | Maximum number of AcaPy replicas | `10` | +| `autoscaling.targetCPUUtilizationPercentage` | Target CPU utilization percentage | `80` | +| `autoscaling.targetMemoryUtilizationPercentage` | Target Memory utilization percentage | `80` | +| `autoscaling.behavior.scaleUp.stabilizationWindowSeconds` | The number of seconds for which past recommendations should be considered while scaling up | `60` | +| `autoscaling.behavior.scaleUp.selectPolicy` | The priority of policies that the autoscaler will apply when scaling up | `Max` | +| `autoscaling.behavior.scaleUp.policies` | HPA scaling policies when scaling up | `[]` | +| `autoscaling.behavior.scaleDown.stabilizationWindowSeconds` | The number of seconds for which past recommendations should be considered while scaling down | `120` | +| `autoscaling.behavior.scaleDown.selectPolicy` | The priority of policies that the autoscaler will apply when scaling down | `Max` | +| `autoscaling.behavior.scaleDown.policies` | HPA scaling policies when scaling down | `[]` | + +### RBAC and Security settings + +| Name | Description | Value | +| --------------------------------------------------- | --------------------------------------------------------- | ---------------- | +| `serviceAccount.create` | Enable creation of ServiceAccount for acapy pod | `true` | +| `serviceAccount.name` | The name of the ServiceAccount to use. | `""` | +| `serviceAccount.annotations` | Annotations for service account. Evaluated as a template. | `{}` | +| `serviceAccount.automountServiceAccountToken` | Auto-mount token for the Service Account | `false` | +| `automountServiceAccountToken` | Auto-mount token in pod | `false` | +| `podSecurityContext.enabled` | Enable securityContext on for AcaPy deployment | `true` | +| `podSecurityContext.fsGroupChangePolicy` | Set filesystem group change policy | `Always` | +| `podSecurityContext.sysctls` | Set kernel settings using the sysctl interface | `[]` | +| `podSecurityContext.supplementalGroups` | Set filesystem extra groups | `[]` | +| `podSecurityContext.fsGroup` | Group to configure permissions for volumes | `1001` | +| `containerSecurityContext.enabled` | Enabled containers' Security Context | `true` | +| `containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | +| `containerSecurityContext.runAsUser` | Set containers' Security Context runAsUser | `1001` | +| `containerSecurityContext.runAsGroup` | Set containers' Security Context runAsGroup | `1001` | +| `containerSecurityContext.runAsNonRoot` | Set container's Security Context runAsNonRoot | `true` | +| `containerSecurityContext.privileged` | Set container's Security Context privileged | `false` | +| `containerSecurityContext.readOnlyRootFilesystem` | Set container's Security Context readOnlyRootFilesystem | `true` | +| `containerSecurityContext.allowPrivilegeEscalation` | Set container's Security Context allowPrivilegeEscalation | `false` | +| `containerSecurityContext.capabilities.drop` | List of capabilities to be dropped | `["ALL"]` | +| `containerSecurityContext.seccompProfile.type` | Set container's Security Context seccomp profile | `RuntimeDefault` | + +### PostgreSQL Parameters + +| Name | Description | Value | +| ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | +| `postgresql.enabled` | Switch to enable or disable the PostgreSQL helm chart | `true` | +| `postgresql.auth.username` | Name for a custom user to create | `acapy` | +| `postgresql.auth.database` | Name for a custom database to create | `""` | +| `postgresql.auth.enablePostgresUser` | Assign a password to the "postgres" admin user. Otherwise, remote access will be blocked for this user. Not recommended for production deployments. | `true` | +| `postgresql.auth.existingSecret` | Name of existing secret to use for PostgreSQL credentials | `""` | +| `postgresql.architecture` | PostgreSQL architecture (`standalone` or `replication`) | `standalone` | +| `postgresql.primary.persistence.enabled` | Enable PostgreSQL Primary data persistence using PVC | `true` | +| `postgresql.primary.persistence.size` | PVC Storage Request for PostgreSQL volume | `1Gi` | +| `postgresql.primary.containerSecurityContext.enabled` | Enable container security context | `false` | +| `postgresql.primary.podSecurityContext.enabled` | Enable security context | `false` | +| `postgresql.primary.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, small, medium, large, xlarge, 2xlarge). This is ignored if primary.resources is set (primary.resources is recommended for production). | `nano` | +| `postgresql.primary.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | +| `postgresql.primary.extendedConfiguration` | Extended PostgreSQL Primary configuration (appended to main or default configuration) | `max_connections = 500 +` | + +... diff --git a/charts/acapy/charts/common-2.27.0.tgz b/charts/acapy/charts/common-2.27.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..54431d62f76c60a456cad876315955e3538a7435 GIT binary patch literal 15622 zcmV+hJ^8{PiwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PMYed)qd$IJ$r9Q_Q8^6Du_-$*(=$^`4*WWLw{+iGOz5+&#^n z79t@DHAS!hC|gZ(Kgj*-ezyBb?t?cHe33-I#@WZ*eNu}A27|$1Fc=JGLOPw&q<1_) zOayZ@jsJ4@Pru*q@9pfU|MvU+>VF4={`Ox6JNtv}{{H^n*5EJw!Pd^+&R?K^54hBx zj0?p6(!X_E)y{n(4@wd$kRUYS2OWSA2|T83egG%Qh#@Xm7K)7F4nRyooN&w!;3!4m z1p8Y-zk^cpGiIF77t=&Eb0-PeE}Vj3|RK zqghIlF=&2-n2t#ZLo6;aPGCqxf~EvQS)KxO0K$my|{P zpyL~SJ3dTsoMP7TLEvc`BY`_UjItz@9q;(I3!Nzi#P3^1Q54eYCY&T; z07r2QXJkAP9L_MuY=$G*=ZwV#!eb&P*-+tYK=(9tIvS+Gi_?sSST(h>W=}ATdlJFo zgN7pJDL#N$4_#+g8R5^(!cWgF9wYx}D9$jyrv+ez{O@lMcB}G#e{1ha{y)UC2FEm= zGbwFaiJ>((KYj6k`LFb1;GaY|5oAO#JAk9pqvP*is%4?Gwgwd$vbF{%N?0@eM@ATq zq?kTF=^eiSL21kZB@v{IhM05A16lrm@e7gyzCzP9#y?9A?X0bJ+}~Et`AUL4NuujN zX8zkni}!v-qY+7nAeaXty%TA$eEtu12HVy7zq`A$|1|#};`#8Q_q=mG5zs~eJnwz_ z)agjzFeB3g;8?(j#8_$)hf_)OaDoq@DAqZ{B4Y_4;B+J)p%FgPj5vn~YmTHz=feje zNf>7l22ZnY;P9)g#RCbzgN=xU0=x@6_rUwdn>QYKdXe*BBPLvc_wCV{C;$C#uiFLx z(=* zEuSe8;pF92$}s0v71xgs7kGXEA3i{Ef#>k)Q~m{jrkEi?nN-%D*Sebr&Km&PD~6IW zhCqKVLz3;tCg3Cdkx_xGUuAWiME3P1mOOC)gO2^+*T->!Sahp#lmPB`9CZt_id~f2 z52J)|j$<4O%HCo&H3av+q_JEwdbb$3e9Yuz_rTM$9 zvNFnIIXAN*W(gLU2ZZ(}luN}Ad#k#s1bs>)%Vs_KcOuC3*)F9~MeK)kn$iR(B4@cU zYzWj!Ym92^#7=|NC@D9Sp-bBil#cOfW!&ui7_ z)=;xnrd+#5Fc*ZRlm$^MScX$jcp(I*$jw*wG8R^D$Fgg7u_%Q3wCMJMk_{VG9#<84 zFm<_d0}P9o7`i+}1&;*gFX(pRBP1k|`Wg)SeKDWZHwL=i6exkG~un~NKyV#k$JFl=d6v=l;16>mHY7&C#`8+ zRCprxHHpmy5_puw?K#`6@uiX5kneL4nj~X}Id4g1TlyXeoNHgEt*+BpUanH6sfgVI zf1deqvxfh3Wy4Ji_MNQrw_u^OZ;y_FVRI3oB`2{V3Ln`#U9Dbeq%$$0jQpvt)Ld&6 zmQ}yI8GU^AqU|7rEP7;PuzCidloYe?TI63)^X@2rbb4}**^Gp^CH+xKY=y@)4E;94 z!0?!G!LC0K7S_GHq4-`-F`5Vz!zqp6C=-;2D8{Vi$V^gn*F$2@4Q{s|*pAOpIGm@=-0+%cMuK*ebI=lk#droDBeq)5+azToz4< zR%oX4xoq?;^qlD{&JBOUm_ zoM%Z1z8!3T9dwT163szS2q!qaSWx;B=}-qG5sXGzh$F}nLE^l?cCa1vwR=$ccuRsY zMalyL#o>^vMIr13v^E6KX-CMY!8G;(&nRF}_kxBR~=^ zFp7YVl&8mNF%IzQ6AW>PGLAK5l8n_fll{KHIy!_cOA`3ocCZZ$^DGt;13=)BL|`^T zAyyO_(JYBPz>HC;@;!e`VTgg@DV^a6E+<$|@DK?U)A2J7Q<9KrmNbpV^XDy1ih9xH z4z8X%{~XGAA2w#c^!@+*SNHiZ|MTfz&p&-y_h6$$9{31?o(m=^;W)RfT<~st{@ZZ= zFK3@13bFZ}H~_4;|G%@fTfP6gx7{B+o&P_?^H|RRAzz3cff-?eLxCfZyg8z5DyQh1 z6eoN_Mxyf*M`L`T=Ua7+EHN?Rc_q6@E}Y_vE4mx6l4LtNJuw1+2j3$OUcQD1tW4; z{n-G{kB{4rqjp_AFB2g5$>TW8U)du7v&z*fwfAOkg+Z>mp$Me{N4AxNLkJ4A?7-@i zjE#-ll-4#@n2`YhJXLg!) z^KGB(ZtppqY5pULGZR`cAxRuIu5hFpaqI9{9l1lGQzB}wy%GOTHt2!JvgC;W#4)pf zn-9M0MydUL9Ucfcenpb(>W%X9;pI-AjLbYm31|hG4u8j?*mPzf5inwOYNt{b3mrB~ z<7c%hB0&AYC1prt?FC#C=|=r7qh0Q$m061&LERzL9jlN*_fyiVnbD?1yp;9M%hd>1 zD~q67pyqSfZZ+D^vE~MhpBElISBNkb;mSssI89=GG zR@h0lPZ^n!7>{uTQyP_NQ$Z7Bm-5KhoA#*wE~;eVoOeCNvU(^Gru z`oG#l-C69PzpU2(x3~89D*FG<{?1eUuLpS^f&Q;hcspS<8&C8WUW>LY9W$g9+l-N&Ql7MP&ps+H@-D)>@1(C;@H)`~*hL{;5EDi(t+h$En;-T;uIfAOog#)4VGAub8LuL#vo_Z{ zdT~kS|Gox`f z#Sq4bO!=Ll{f~^P%{WQqR$Oyuh!WX89ooIS$fLPNG~|IBy>^Tf%uw8$&`V#?o?tW^ z#+Xki75)UrQynVN*L#89TG4r5v!8!CAu;yzaWUo1$nYC<@vBNDbE&aZtj>@hVT4G$ zVqfvOSI;m1sq24aipF;r`|&TU?|=3CwfK)adwWm%--A4lMgMb-VN*s^DF7uOs_XJW z=VWAl3N%&=SVYE{>n*Vk{w){MXcGixQ<7+@IYMzfMBxS3=W2)vDB_a`O*)NXef6K> z>bLrNMyX>~v`UqjU|kwKZCEIZ=-=R}hCK*$taGKrEL#7|&F7k-@rIjAEzON05#)#k zwg_x&;8MzopasAZAp5bXz_C=Z1Z8T$KX5Q}sa=L6$H_U-at)u#pi(aB zswaUSDR+@^n>jQEf}?yWs|_tPL+K`p)(s!Itrgup1n+-U*1HNSH9!?q8X7MTXMI`p zzT&;Fxcr}2DO(*m2h$Q>wG-}o3mW|OA-3_NFw^%14KFZ*6E!<58^XETZ-5G00UHrc z84i)a(E+Hl;L<$Mw)WF3j&&_=Pnf$)=5AUPugu_l>#=YW4>lKn+v+Zw;%%mM2`fj9 zcizhhq|lQzb>lQtr?f+mZq?X)L6Yc%gEvKKaXUX}UbnSFDGTKomfi+Z+?H*-E)%tf zQ?n1(=4GjmhEAng=8Fr~uZCG!*xwuWxUtVS=ylaDzRXTuh`y3%j04!5g;YoXphBt= zE*~LF$R9Q!ip~k4qQWj4m%E$Vc!uH(siO&FrjdIot7I;jzqLt!=d-wCQCKl^8}L~@ zf6dp>IR&(T*Jtmm5}mV#REx4vT=BpFkNxp~d-jL7%Blwo5!Q5GHekLBBvWvb20I+V{-is$gJj( zsy@6$4f<5pk_uM!cszK6}HM4trbMquoJ-x4%LCZ}#@WT|DX! zN8!%aaC@}By&LXt5BmGV{eHh^5Ddn2?bXh}f3>qyI^J|V?|%EA4dr(n?tM8#$i_Y^Xe`yD46T$QK0_s4IzM5a=+bNansQqSsRnI3+ozqAMW_}PEs0|X(k@E4nB3$i}Oi9~!x3+92 zuiZOIL;&iQQU*6DgCv^{G3#2-Hd8Ht69Jbbj$w#FFqCjPy(6h}L}aAW&j^^KY3%rq z=Et4LoQDEs5>1i_JjS)7&KHt!?m6dMbnB%S2U^e#I3uqWPL~ym?{XkZ-_^)gmvHk>OIqnIMGw^RLYn^UY>Z}6jJu?C%d zxy|uZU)m8&Zbgj8xRe7@2Yx$Gjq_ajmgH)|V6SzY8YrILEv#bMdNqg9nl90Q~&r7cJH^k+CO#u-$cQFIRDR` z!Twh5{C~gyr2jv}^Jw&cN15jWB@tqgj^o~VT40#emMrpbG-lh-mFm&jm*4!Uwc%H8 z7ufkV94nO~``hNb4LL8mHATI792?`_mqt1X(m)+e{&m#XW;}8H!(K@ zp5idzCfkFXy+Nu1d={1qERiPV#1G2^ij%&lDor}?Fht5r_!1@RYEn#T3Ur1UXkbRH znIjnE`Z`sYnAHB=;K@l6Vj$v~3V%IUcQRvZ5V3oEhS7x+dz5e5{XgFXEW)7kJ-x&; z%r-S3GL>qc!Aqia$%yij#Z{r}#4KPPT~hng;;9^yDHbR~0vXboky*U6Z=&#Bh*MB= z88%W9UfkgPYDHR`E__sn82?1mxKUo}3A{{@c5Rcl74p{?*4^SF)m=)e>q?!^uj4*F zi=VpwuLt}N)&G_H|NeG0|HIDi_EY?a2YDWW{;yDYd6mjVKrT6nF_5b(txD%uxU9Is z$uEkS1P`jN5<_;~mL=cJFk>XbQaZ9M31M$r{Yj?h*=R(r!1EWSEhYLxoWUZE** zwnw|js4T;Ifx2EzS9QQBbtUVP^3(Lc;$FEU`tQQ?mEkl-AqMYj54>N!n|BK3gd1gX zJcmCr6w7gqq@H5ju-{<~U6mKI4T(9=Z=G{G#qOz0VKvldtC&oQIfM`s!ePUZ>c#7G zSyr8dq&VyR)xk3-hlWyKb8}ovZ?BDDl?zMIbi3DKw&g1SN+#5&R5%IeUnDOsHl=EA zEV}0~rrmfs|pD2IlPqb8LR;6<*4;A>t$ifwh~B)YcO!V2X_i%r4g|UJi}2 za8Vx6Vp8Z9s);}olu&Q^aY7wL?l1dxV)PM>xR%+f^HTDL3?s9z*zJD>8~7^3sQ{c# z@Dwu?`&>|l#(Fby6(csry)FG;;N(xtyE#hhmOl3Ep#uhY(;wrv?b+rFB_z!}@CN<< z)B|sdr;3|~H5y_@E#Cp)* zT1=c9pgq{#UOaYXycPeqW$U0{VvzpM?btflEip)czb#u|-2&^S&9vd`GPu3LPFud- z`kZL*mB9_Rw!Ue{+QpW@953X;Q71*t_Y6sduc{yGA`hjh}tRp8-i! zvvjE4hXi^!|L?8--eAA( z|NZ3u@gUD5(ErNr-f&rN)*CbzS48Su=mRPIIfeoBgydH&}z z2k#0fA6}MT^zztKIvOI1wU4yK#vb=NF5vc#yLxZVEtQA1R&ocLX%KZh5Wh((11z7EK#F!-7zBYMzu z!^;FD(%uZbCm6=PDI!VnK@H-X?Y(YS(X=)kZVa!2jwi}d-M9$Eb1B9zF-*`*c48*Q zewCtJ?)=>}o%ij{Ugpr60c*8cpyacjTiqH6R04fiwLcg`SH0dfO)J(9q{{WhLaJ_V z*8I-975AUSwXj*7n|yd0O@9lEx`-AOu-$Jq6;-9q1)jGOIv03;E19F}%YT(w_erok zgkX{CS7SK9*UovPEM(<{s=9i5tFg>^R023Sgg~|CPTPiAQ;HE?pEuBTZ57HZrKeujzRf=jR@mH z#{|U!Gjmzc1_;x@G^%>Mz*l#V3P~z))?Z9d$A)hsU?_>`G$)(}qlX%N_?FTbqofS# z-2|&>j)DS;BH;7skjC70c?Ia=WUE01s*Hy|;8Q|d#nt49n3EbgzFO_E=aM`d8o!EF zu}i_P1uvCVh=q>P?*5%0i29%pmxRHo4_wfsw1d!dmNMCOHeyqL2Ij* zq4fnxzunuxN!X%c)sWk=#AFi^>Mls?(ALBa9wLtSb^s?Ko2SA~2ifNTRz9q^X;OK? z^8Ab#MJl`~qnYt}apzEjRJeKD#SAh=ZWpRjmnUSbl7BEl84=3CG^t!pRcol6uareP zy1dRIr4G(VS)$D5CTgx?u(E`gLTeDfX&$lHU;#6NYB~uSH4@-Z^+&I28z&>RP!ytw ztG4WEK89!Ijy`h)f<5og(N_0emGH^M5pu^T3L|%)GmOrw(kv#gV9e7P6 z9CbSYTT+M8>s(Ijn!ql4j2fi5?1$o^Oy!Bmy{B>tTY7L)a|s=^`xO!m%@n!9ik=m1 zY0B$Zx$x`)&zCkMY%(r~Y=l?2tyrC!D7SrUW>T}|--?@d0ytBPNIZAel?pXYkB^kB zHET|t;AV8q0?AVx>hp8cg=hN1v(hT75h@y%eJjvgsYKV6w_Lqk&oMhV1kZy!ETvh+ zDzA%0({U2lD9kvDpJ@{^=fxZYR#%TOB+@tWYa%5n^dLjHuhm@>w0)zAc2&{BBt~rOTn8- zCD`tFTevRdaLsskgGhpOf?_%ixf>&EnRh;`O^O>?Cua}4#i^D42*bUd2!~FXCv&Y` zhno5Wf>*X; z_GX3%n#7zFr>>yU0su}Jr{>0Gp9(ncAT5BnV2oO|?~GDq(_0CaXL80sdBdBFhC^2# zG;D0EiJF%3f&p$XY@a$}shV}6d8XNosAT|~a6vJGXOZ?C{2L}`b#q@uM}<$nQSOL( z&niu&#fa6C59p*0&B&C&+*u-t#rQPJw5nmFGW>zr$kjOMT(G=@8!^4a3^wG_c@(D; z1cPo@|9qWIF(V-iy0DR@X}#1(lc3>O51PpehiXYa;vpfm#c6RBJjPdN+6(+Bj$aX> zjNjh-_wO7MsYu2j<<5@_2D|OSyD@{koE}99XWo7UKFLO-7}o-bEbp(R(Cciv2&WH= zBFI+%&XcVbyTs~BujEgG`mj{08YSA<`PCfzT+*&^`SeOn{!s$BEM$br-d1RYDwtk< zTehilH(nC1qC#*W!eqwLs;AXxjNzk&9ZfIt*R`IRc78S&>x_7w&b4&^LakYDrxrl@ z+*Yh>T5nb=;&$|NgZ9iSoSyUYe)Yo2#Zb4kjRhKEDG#4Ud7(O3ny=1@ni=LgoN|GZ z#4{3PfjBY{8f8NH)9T1Pm&THaAZ2()XvXW?Jmi`ac$>+tORk#ipKbPDle)V^6n~&q20!3Db*7Ln`k!qlByF9sNbOgiq-h0oDd*2Y@eQ{;IZ)iqs)lH_)Jv;vW zpSt`nf@VC}{hyth|L4x`Q~citc^-lMH{w5uFw4(E^hs2H?v(r8rI<}n%JqhbhcwNj zRhl1MUja(QvOBj8abchw7^Y#-sO@CIsCxGW-cw!jU>&9D^1z7o2J73mntRdA?q)Dc z5S!Z<8^s5z%ke0ksvdC zuFCtLKIK~@uQ2?0UDz;zel#6RwLH^Ww;YEco zO{By<^gbxNd>~8c81SE@p7zmtO!_J#XLU{cHY0HaIGMo=G3_d*?;9W;hG*qKR*0fU z(T>b??&l{btB0ln%CYgQFX~QA8WSb_x%}gm^8NNb+hM1MI@~=*9RH(MRjp%wHN{-D z4fh~=A+#bx+oBR1ppTgY=r&kX)X(C?c_EYquKJ?biK&A}vjXc8Tsd+}y^wP6dHw5J zQ>+HKu*1pT7@sU>1Ou;p=F@zfrB*)iX861OuwL;osVD+POSLN;4jjM1e<;;aco?1$ ztON5%(aFsDAsy+NCH+pT3_xcR5`5Lu*Y5nGGz{NJ{&GPhRRQ?W^()ri{rZ4 z?)jfS!IJYTeS~Rg=(sSJ4l#i;Q_`FgsVSsxfW(l{#5bkeu-sygyUJCL3p^i``A}Wp zxGpD_+N)jwGTm3+r1>|7XP9yPgM4{#2ViyBd;vPY8y zQd-KRu?hG}(#ZyUvQdj+gJTS9gKxI?_qwY!iqIhZ)?k~{Rb%Y+LWR>5rRseDxfgn?R>TXuzJEAj!KRiCR|;iM(Pf z@e%k0ZSC&KA$zjV|C>Ga{of^Ga`xTf7I69gZ!j3_?^f;qTf0y3zaHdyEc?HAn(F`! zX(k|(avvCtVw(u*YsI^xv)3oDzdL}lqW2JCfkS~K*pPd$ zq8<43=|H}bWj=lCZi3M<6CJBxX9`e0HH;?Xcn%E9ZsNq;4MH^cG*XvlPHfWpYvr()Oxj)}UD#-@N1)M2@sIvc+Nx^*SgBY1 zh`H>S(q2(1@Ph4mQN5bOrO>(Dgz6s_q*>QH?=02;?PVRKKW-FyWbZ3}paLQ>JSJSQ zd5QNW*LNE((iah4%S}|eQM%(%rBJc`u6(!=cGmIPrSf6n47Sp(xm;87?f>`x{J(Ji z^7yB-lehnbTx7g49fV>M=sTW6j1%qrO++SibQ8kidmK;ACE-hzPetdO+f)G)<$qOp zbM4Wpqb{l#v1yD!Y6~OErrbymWbcWEO4id6e5(bcg7H>Pb2uudIUMV0?qC|gxkXT= z9#!6sPDcpOQ=m}LF`gr=?hGjZ$4p&bm5rsCNz70Z;!PMbdVv$u$q_~(W0>oXO$k@1 zJF*RCh!Hf5F%LSO^MYPh7Faoa;BM6_9Ac8q+cfhFB+n`-BsrO5A?(&A-vF67m{LH; zu^Xee-4bboP`YMOlcUesCEM+>+!x!egqA@suh2A&@qr1AcJpRJPRw;BW-r7slWSM~ zF{5!d#iy95VNx}{hF$vG+-8uNuqO&XK%8e&dxWO0Qqnl4m$_fIxpAs}SetMu`jBVi zt-Y+_SovQ3TCHsq6f4`R%Hpd=NuBizV>(hsNNwIMqw)@ex&fs0KSr~$ zzRO$We2(!i2*T2W=h1+vXn8n24LqqpkNq;1)EmzvZH@+n2(uDKqD!0YnXe( z%G7k-_0@}D!4Nd^iLKPgD26mAHbJ&7Izb%F^}$0uZB!r{wL~4$ED?wOO^B#!#tJ$j zihk#KxXG&uL=5N>8hMo}*0yk|tU=r2sJPN;{YF#3QD0n<6Lf1Wub381<5Ip`+e{Xh zz+M+B@H7J_7)O90MEatWpejU*P3)kPNJC#r8aXyX#|ToPO%h#lo_ola=w+Q@$BlgB z;H48%ccEV=OYeD!N8sw?~vYJL&-bQTkm%6Ny!UH}I7dmu(5;NYEBt@9_O`12-~0Rh-6#9+Lp+bg z{(F>Nk(eMhcOnI8{~x87D&&km0%eu>m`krU7c6WX^Q!SWZ8Y)nzOr=1(S~DaiozA- zG2V`COL=5k#EZI=$rT~6Ywm#wL9}RNxDsu@>~5W-=&Xv>U>OC>X!sMytQwQjy`A2; z)v1GQ4QO$iqU#O3iT6=-<$7ap_3Y+BZ$B7ieSPUDxPBCiN5pn)3GGV`87k62b1;-9 zcc9zS-CmN{<9#ifU*Nf6lfoF3hdS}3a#ueve{{3Y?Zk>PugN`?y0~)O9g*J ztRu_HIk-iR!6u+dA)}fD^0teCP>wEbgN~}5rtPSc{6mL6D8&cKyW|3SCD_@{X^$`mvMBq?ltkH|EijY&h3Mmtl zQ-(+6ss$Xmc*qJB7&ctk8KuGvCgvJSoKIe<)do0nNlD6QsS-wJUazdb0Ee_~`)4>m z-doh2dWkyJPT8;sUvajY>(RBIMHSWyfgd69V!ED@V?1cxxZ?CWbF8G)-J?O`9;aKW3%8kP?uvAsiM62K9UGhE z{JqA=7HakvIjRNvD@N3nl1(G#zF%otT4Dd8$(Y`^{bzf3yLSGwz5f*d=RuywV*j~6 z70a;j!>CxYu@}QTkq#~JzKQ5JV83h?%XH!z<9<^WYXOwos#pf>BUiCnFT`akJ@INwC-DWG4r-lw|IdbDq< z^EJY_t;VN-K5~7pwPI1?&j(X0?q_=4TAR@G>I*lexg>cQ{rz4>v%T7$OT$~6(7xzr zx&D_@F2)SsQVCq4|LyGzD*E46f3W+M|KUNN$F2WGI3y9ybKhV&%aOpK(<9iVO3MVB z!@;I>#&KYCK9u6pUEsM-N51{GOvWw9Diwf=t|u`c;v8F@Qk5hIYwO-sQRx=Sx8*%3 zi@D0;V#wr|eKDF#Iqf(H|N1mO!dES7nJ{&(64>^3);;e5>LhHp2WUSei}mw$O{j%= zTd%>O)kaqMGc43#iZmmYF?Dch*6q9H?kv%B7PfI+z<0cbaJqO+j=9-pVhNyI?kL>B zdfeLztAtvNxpm38<`78bt_I^?l~hN%-GQdsx<~gSJ&K|~&$vHQQ|`QqPe)SKX)hHTtZ({(p90Z0CmUm z&TTEdxyWnun*M^>WnrIIu*?FMNGsFa<%ebE{=N70ZJ*`)e}*G+`#_+p?tky@_p9eW z{oTRS{{JDKd)@!v;{lKn-kL#|$y8n9c1nCRj9ad78t9``-BW!VN5!SL3!3hIYf3B4 zR)M+KwMw;l7t2%?d7fjxc$jq^cg&WPUI#wUtywzYmc(B{e8w$Bb=r3o+Y~YKCo%za zW;#|k{QVFHJKfeJk;B1JFtg#lZ^8eK@SIJMjN6O-~Cu&;PSR^`RS54zx0?fKOP zOia8RUS_IdyWlR96C=O5d3VOPi0t{f<-UEEumA4Fo11F^E7t#={i^@RR)6a$|MSB< zkH!9<-~Tq(p=B9md>G>TeQ$k{QI%J-@0cc|eqW_uu3n7GvwWDGObc#%+Y51ali>IJ z=2qT<)&_Um+8}SO&E>a6ciwbp)kfMhb)g7ILW&3M6$`eN;0c%#0#T@GWMsEC+Rul)skllEy<`?{Fvn?WW*0yQ_W z_>iZ?4aZ_VF;QFd2ni*V+-mO8IaMl5RPb<+5A?!&qb4alBK+2uFC5C`7~)BcG6V#12yR2m%C?+=CPlP5at%BN))ZO38UaTld?Q_ z{7Mjnn`UMzX56BS^jhz=9XmM8vo?EPDYB+l>`=P)!oBmRZrY#KjQVc2LOC7GQdTN5 z#^N|*3@0K#nee>o(Ev)KTym7s=+#=fR$4@-eie;kqXBP=J#DCqXx2V>pS(}(rS`A* z`=ntzvLKyf&|Pqza5(O%^K+YP) z=sWK$0c(_Kz4VUVl)r|84EjV%RdW&zoW8nYj2Jj|{=PDw4s!@UzGl)rogHG_`{MU224t3VxSg|bpe0&ZO zVZ0NJiRh_+HTs=k_$TYBf9;FOxF`RyKlv=_6@Z2)yvS0uJ>i|_0l!Q;&x0Yl=sXX^ zH0?b9zdLL2Gh&2h98O-mT2OM=ySS8BC-5Xk+>OAMEvacdGNhzx`zY ze~@P_&(mUN!z(gmQn65peL9^Z_(f%jDZT#Jh7AxcmyLi=bZBTnQxfuCtc(7tRx93H zlVx<4#xbK=Dn*LsI*93*gfPV765}LCMAr*CowYT1`|7VR&N`jne)~--znuuDIEio) z5^NM~x%?d%cxov&CdmWX3a)}HdkSc>@*DsS$w9AYGxqp{Afn*~W&xo+lgUdrFPl{D zhBVFQ(8d5-J|RY|yzNNpt{t!pe@#ttc_qcrVP=Jj&u&yJ)BY z-L}?ru9X<@zQ=J);T>ghcQF>wGfoB{8%@{a&wNwD}BHZ|Y!CN+mUw;1a5;43u zJx?*vhBzv>7fu9bDI*+rH*<{zvyh+|a6}XUql@Qbs^RHDJxN54NT;Kg6s_5q+$$WA z<&Zo<=mf_pW*jajB%DBq5~))uqrY+!o#B|Kkl;(hJtixW;@ujzcI}b|I%+u!I-N4} zl^Rg%(=R_{LyXdt7tk)un;^ooo@Q_-i-*cEq`<46bfmK_9c%a`fiTXvz|1iEDZ^?% z&xydi)A8YlJoGvYg01bZJH7_69efk?zt(l+MiWaI>gRci)ew**%>?jpf~QD*S%VXs zRIK1tI|U?LiFt|-fUA8~2Oz>cWJGPQ4&a5FACTv`Dt3)3Cz49bL_@i`>VVC@a{&3Q z>U5mhx1y=DB72sko`x@HfeYE@+e^kIx$1NT8m|JY;RrN#!3=`IUNG<@JR~Ub2YsLI zZFf3p7RRSFCgDn46|qNiKpOmMUNLy4!D#@2&}CG%Nwwp+jwp=Ye}ML zAd;E#R!uvwQMel;p3fWJ4LY3&4>N~KLw%lB>k-zuA6TZ+cg$%9mo$qbm32#g;TQwH z5)1)JRDvx%(UlnIE^YNmn`Fr&lh+^#u>m&32c5N?n_Na&E6M5dFt5qsTQF#A;EWoa zj9ycrvM?l~vj)2B1|uaV<#afeLYfPlgt(Xx<`i`$o$S%0E-!Ud3oCGmAnDlYa6uUw zTneP#9v)f20v!h3=6m2~!#sUQY}0E;V$9QS^=xf#0YB;N;Jh zjh&M}@ikib<~!2q$ozMVwHioxSXQy)m{Q}Q_M5$EO4yv%s`&?_&FjJi? z<^s=^z*h2Geo35`<;OfrTMY?~zs_#Al-OEx%28bd7uhv{+{PyhS?97J@H{8wnoVjY z5zC~cdMEe0mnQx$aGY?WcCczLs*918{9MQ&z6qR8F$glnTmra6iJFvSSz9Y&OrPeb zlyfp9F%fg!tV!%g7_U-8Y6Nz4*9uAAGqh6gecx}^HVsv7u4)3rXozF8LZLKmUsVs` zn-u+#;ap`cM&rW=C*i3v!+wO}-VRQ}{NBi?Pn}Yyqckph90Y+e|KVhIkjJL9yMWW9 z^YeFa&R#evlV;ZFdf>bSLueH)b5#Dagj{xXbdQYzw-&Fs`I&RC)5RnoaPtd$4FG*y}fMU!DizN|d%xw>Y@%_aFA? zwm-PR;ceSUF#GvE{#$&pLdS zQYOFwbGW`Cw{xM0Rb_jU<|{duq7dg7nhIV3pTh5)CKA0v??WIZUf^)yCr^qu#PQw^ z_))jhM1sMMNHB0oFt{5M4DNvhgDMG((14%PF+-8mRFnvLOJNZ7gMO#;%bNsV(-~GN z{s!Bdu+`t{Z|a@zY|C1nRkmWa1(DmM5lIN2;HcP{kBOLMLuIRw%-hqO`ZX?)$hc2O zzL;R&7;%*egK(Il-zl@!Be|pCimXthzQeryg zE3w{H+ujf*lBpt4d0O4guFlOY$?M?tn?BGEIzId)si4&$V+H-KhSO|2D4{h%fArQ& zXSv$I`K6q0k2JQFaIq6;N+Ae?8Iw{KGG=w==nM&%(+ z5F^wkcr+trj4p2Nh+;0Aw<62VN0iLvKo)2ey-@pv%4Bo9rYDU=n=iw=OboM@Fg(J{ z3aVe|Xhf8)P!)@4n8}@u8nfk-XSVh0Z2Q+K8Jo0^Yx$pk#<3qFj(OKi6Z0t<>%p^q z5EN$HhFgB(c$CEuljK4fJ^yCg7C4;9c7vgDNL0c+<2{`8X46Z=urE;ZXV!B}+`cg~ z_tY1^=?lkfMncSc0)>7=Ls^~sA`_Gm6mylnGM-^yc703zyX~ix3%}^5<|1ERiVr4Y z8votJyA916D-0!ix(xOuy;SS|Y|9ta{JGuxyIMSr>t)Ar+x(A^rt`nb#d0Ti;neO$ z0<$T2_MNBsK(UW~r#(GU67?vPO9}97$Vo&HBPzCnX)b~+iHz6!QHsI|wuo$k5rnW6 z^kG95@XRN#``3=-@hO_C=^|GN#j8pT;j0j*N=$`xn#M$L_3aX8Km?tC8US=CkdjQY zvvy53r2vUeM-la)*SoyD43I)GplsZWbrIfsb#naj^|^9T{d=eLQxap&i$#4nx925t zWr@)xNP#zIST95*flEe&I?CpBBqR@ZBEkhD!%UROV{sxJ+yZj_NWeQfhm&&;zCAiW zIp6HOJ9+#4o1fmoyQ8zSqt|awUY^67GdODc zVQyr3R8em|NM&qo0PMYccN;g7C_aDdQ{YEsuBEwZQZL&Rp3R=CNQ$G49$ZmQc6Mft z1$KiZqGqE5pe1u0fA`Oy@G5dRL*E+)MZ<`JCXo+;Pg+xG%A!Z7mo_C0#A>p(Md=%J4>p&ZdB zu!Rc!-R|D&?yimF@SqgOZ;do(CHs4Cx`!^*y~7OvLhPf639cN)(4Qi2zq`8uWBfCs z43nr2?)Nuf9H&1On2i9%C<;*IW5oI!hA^MZW+d7GfTEZ%%w-15W|S?0L%ePV$pd_)JJ#{fjcy3JK$G>Beo-`$LN9W08a5_f+&+<87CA4Ag07e zK|&GhZcK^b;*|54^?QapU7yT0urC@~@}>tFL!9*(hyES2I=qKx6YHlZ3wZncyC3%t z4!dzQ*|`VS_c)$-6CS-gDal|2x5VfS?drDy7 zli3b9i~KG)3PW&>CsWSAHDZX~qoBJ1KtjW;VH3=!$w;=#h_Dupg5;|{mFOC4_c%qU zCx|Q=85^l+?Y-{4?jHPg<4fzZm(Sv#!u%f+|8C7V8s`7qgTwv&{D1KF?aTcC6rabL zkgQo}|3FN8c!C)312%>Guix~?qu|Zq!MEeR{Qw2u9)9cZ9=?8kF#6Viy$=ulzwW(0 zfPWqDzx{T1@9=H#?c4p)!QNpI_`%_uZ}<1$-r>dsMTkOzxHC;&_Y^?SrGi(eaO`(h%O*+ywuRAzzp~;9W>Y zFa$BAaE3UdOuQY02r{$-BEk{iQ^*0IVg?>?7y@#SD8+$zj;v}s07rh91UQ-iTW#$C zpG0FkNrYL*2}qc#IZ=3}SZ{1@Zm8eFP8QTjxVlVNE(ET%W-|nzNcE-`3Bag5S=+3M zOpQM1bSl9Pk}w=1pCZn3kPS@09z>Ne>OM7{DkJ} z^(CAkhg`cR`1?Q0C=SpVCLtekLg54*hmfU2>sP>eC+z-#Q1*D-e|x=)#0g)87Ngn6U9d z`b9KU2vx@v=>Qnaa3sj5V9SUs1GlAsZnxVJAfO2`0HX6GQV9HnaWYegH~~IIkfS0> zQ?)IsxU!8c5ylI)EnPGg+m^nnL1)UeMTb6O#&I-J60eYwF))wKpwkLN3Uam{_9>E@ z4Th{pi3|C5yW5T+h43ddXI&{ehVMV2c}m?KngblIgUA|ex7%HC6@_yFGXM`$6oK1T zOuPk{0fzYE4HmNWWbMr%`vT3iR{KxZ>T;ZGYrOm;%JsGLEU)6U&J`b{imXR*v6LCm z)+3h$>qXX1gC2mqSX;#v303dPIh7Wv>u6yHVIOs+*UEZfcbF~%L>Z^Ysw$@%Z9_Fx zmde;nxz%WEN=uE7V={{&$Hw&*z*u{9r6~QBj1Y|wM-0Rv{~T{E2{>)~C+ zC}LAQ<~Gs9JT#ORnCPJDrsca5{1EvG#e9BDB91`hDo3`6pOg49$xJ7HZR8BEfl)>nNohzQt%aU9M8Hm%@DP$ck1 zLL+Dgp%{ZH<=Z=g|2_g+F`^Q)sG4;TfZ+q2v+W%aU(48uJ^LwRe|{kal{5D`Ur7BB(tBqLx)u%5nxo=#I4VkW;}CP6Se+ z2E%!_LQsy1uC$!H<0K5F@x;+g^bP`Bay?oT7bGvl|j0h89HhkyCgghX*(ks|jWOa0<0UpNV#; z@uS9w&7LhJ#1#se6bq8HDUxLtXt|KEnj!gc4o4_t;3x<{sJ?O{28T6bg{&j(iHc`C{80WP(Xm;BqEGsAIwOAfR+`;AxGmRWQYqWS*Z&W zAa^0@zU!h$4ZsTcTY}t}k`dBN-Vw?Mtxz)33@5Xh_-+blVGEEPymH`bG<`6JAwzWp z8DPiyFDIGs3SxX>HX_OzpG_B{a$oPNu@IrS4k@G)29Cr(OQ93h4K5swafJEYQAW0v zRHc``SFTCBtXk1$ng~!d&h}EK$;fy%eKPCOlC6&(hZEMbL{viTrtA5?>j|I_u20{c z4R5ah_TlpA;`Elv@iFh)Ke&+S^u-ekoFqfs)+DvW`8pr&@frX&di zF;=z4P#etBk8V6gsna~?T`$>SlN-Bc>$tE3ZG7s+3N%E)%-N$Dqh6mVA(BJ!)seIm zUWo=|y^k4qB~(1)uXX?mnQVnDem1@&d_WOH5r3t?IYZ_yovyl=^aA3uo=+kl#aw>T zBfY2M2zr|_MV{a?3Ox154EU@w`@qJjP+rAq_c@#cX4qY%@6%fw~RlO@_Ew{CRweJW2@n%%agFkvGPaagQcNg}nks zDFXr}^vr7XNpXo)Y98T+S!8FrM=j6gTyNqu#4-gOF@`4*fa&U5_I#C>vJ0;G6wwFF z(2iX4a0H<5BbM19qflrk;|at})^m*wn}EI)vm&WWx>38}Y!b=f4m>V*wFw;+Q*w_3 zlzN0K{17>kT02$^*qjd|-@?V5r%Sf1wnYoMQ`2$n`do4#Eyu`vhhKWJZM}CSqoiJ6 zKKziDs=`w(B6(!X@vsC{dE3|JF78(C0PN)5<~!2TzpdiPZ8|EkZnr2NV>v*R7>p^I zsX?kp>w+8QFA-$UDss!Vr;qu@i_ zhMqhzYF5Pz_>k!tb)&+)m+Obe^pY1{p$(4DYTDNA&|V{HkK}w_g2IiW%!6!9KSB93RsQ~l;Wz_2^zvvBj>`(tnTx69)nudgnz-VeRwtBZ@Xn{=e*yPyv` zWIPrswwxV(uv^JM(FOXu)EmYNX+4)KrY?BT&^QT|{Sn;5$d|sitdutD)0IUIav#j* zAFOAN-%lIXgPP5jw2<5=QNBLATHg%=0Iv@Z_SJ$Wz&s;vb8{UgJ`_N4WP2&(qi#qh zKN7~JL3K_hzz?xd9aH^`l~p(Lhh!o(RvD}l%=~I_ zB;jlkfbm3fPc%e8a%+lON>9p75>-?zI8nsh{>=kBh8&98l0o{rf~3n7>Z&$e;OGJ| z1}8$3t1ps@5Z$9tu6U=AqRhoDZPF4Zo#O}%C>rCB;Kpnq2(gy1aD+gtUT&G~9Xyts zD-7}NGI%$5hW+&2~`*}wrEIJ)66D@v>yx8jAn>5C36mOSwTnti=tUTkSdyoJh@zu_o7k|IqWaM#Zj<0TpR^0;HFEICBVlIl~SWx1+EFGX@|>_cy;BZVq1J0<)rsnfUI5AQ5)idA z67T=7WIA*lpaszW6wQ$Fy~@QiyEPC+XAR5v$kjrFsWFTh2vAIs4><}-ILAX~v}h&c ztTJGTQa>;!dSwr8&W8X+KAp$985^QrzicZ}skStdlA85;Y|jNs4e1|hz?dIW_N^cB zgQ?^8uJcs&j(H@xs(X&83rLc=G{a#O)V1Mt6 z=KZs$=)diPvvKN2+DUho37;aWAZPCHyiY`%``3$@`$DulNxHD|(`6*Zxe$R2#tG!` z1Un0LdDt$%6pTq2Nc(1^P`(e!_A*7yQY=GZHU$HULIQ(xJfe_d#DID%#6Ua;VftcA zZV!752|yf)S4>()8%;3#pc7A|2_)M)iZKbc*tWFbNWwvgXV`50ixtLn24-kR z=v>a--_O(d8@1Oa*NdqMAAl|Cw^C6#bKR}kGD0uD*tS9gZhHZ`@3HAjj_2DqhZnbX zy8;TOr?@gt`P{>dC5ZJ7_ukai&ZxA%>beJSULOi>vgu64S-Z>e^l{$SLbI69g}B_y z*K$%ZjmrCb6sHT}1qC;MhK%8Vp>u3j{L<%_sT&ByYt2b*HwmnK7LV16P%o_I3sF=X zWU>J8#S)sOx;|yeE2cYKK~BTuHA7O8`e5%JPS?lTQ#GuFF3j7k8(Pg|EwxqZX{JOu zh2t^yQyaE9AVUCx2`BH&*(G4U$tbHC6qAeG+(hBnV|WswK+%XO$73<`WILq}pek%a zQzJT*di)s2Q=zYZnIb9h);S5K=wC5~OqK(xDvEr>0EMc?6sitX%Y|3ju5A%biNpwk z?3U#G?6AZmIfdNyUYBvA2(#caPJ6@Qx$ZCqMsq;XZwXRdmSK|6=HCLYs&Bh*)VwuA zd`bf5OkHkk${S3>w6)@k>1XL*bsB$-?um9Konw}TB4q&5X|g0NXh87{(s?c}C{|D1 zfvz8R3%g$WMYgN9g(l|V4wykE!&X8B1M#=p?WX!uAHG&aOOZMHr;KnJ4(OJW3lV^$ zUscE`WZ+o7zku-)&PFC?Qa|T&bi32WUg%BJl6dmt2p%^zM|+)IYdWWemu`a;$avyS zM^LsSYlWN~Hg%{)fzUqq-7`TK(#0%oK56&SM2j2%(p#6lk>%u*Vwu@I6_weX$<@i; zxBK0_H-GK!c6WRGhhP@GPPJzVITb863R0Dx!MId=rox~+US*w7WcTIO&1oOpmWriz zxL0>{VP`PE-A!W00|m1wv{lWQ7TTITFXm^!QMhlN(pV0 zh615k)6OEygHfYCSS7|tMULTU;$ex*gLIP2#Qd0^m6Xr(Ck9QM)ms(XYDXL@%2i;M z4Kh1BLno}{j7bh|M(Qsx6h?a%)~ACzLNgs2=a5AOr!Znr&4MAB*y!_sn@LfbVi-8V z5}=R`GByp>FAW4kW#E)G5Y&uClL$Z#WULby5n>LI7|UJR?y5@q8-UsTgTVPgz3H;4 zNkk;yiogF~Z-k>Bn>tUCKP8}ZLI5MeM#0gf+i{NBXhh)C=T>aU22O4WwQQssIyc2b z&bQ_GZcB(wF}LnKZDs2}ZRiDC!r%~d7q+Z#h9ZVJzDIV@;C4ydd>DZTLhk?!Ni?Z! zoZQfEV00M=atFgIn=dC_Bb2#8l7@nbb?QgtOTXe2l}mOSjL>4}8n0~yUOPyy9o}L9 z*nlFbw;oYN_BKhBMY4K~L%F<-DH7WGq*5`a1u7IrY)EgXI;JQLOJsF~#)Kjej26=% zF-7auBF*Zfz>i7|lIKj;-1f?&fbDis#ZiDzqB|C%v`Q5eNp-YAHQ#P4HGw>|s3Wm~ zUKN;wQLk9Kg3EU6M#vmGiGor3LYR%p9jMP#DbN|;rL_lqN*GIz=-I&z(zB=*=ebf- zJedM`4{@kdq-ofHBZ&eXA!WR#5#=Q-gEXKUs^gB@%O;&}V+3W~knAV5iYcSeMEI4O zlA0ZKt2@KbKP5?+g2|Nc=dq;94N$S+yMjtW25IJHmT!O;e| z+|9j_+LhN12MW@7= zk4T_hWtM-`#$uf|P~M6kuC6vx{U_tI`k*s{v}3JKvfBAHB4rIZz9>f1W*X3P{G_cE ztz&uDbg@Y}Vva9b@wFll>;-!a6t>voTi!epD5*1`6_a;?Hj9v_= z^E2D|1A0~6B3CUn2<7|M*wl)~pvn}mK4cnaXU5Cd@7fx91wwp}BE;AZpa=$7eATHQ zA>~P|PfD)iTu%1f;Pg_Io<`>>biGXrh($n-r3TJG6v^)tI4?nkODttX3;1I4#V|ZU zA)F79PojXyMKhKOdO|333CX82a>=gS0(y)nCV_!FkiS*}$ngx3gd2!A>gP%z#}J1J zMK@E5*p!3;_(44YJbkhZSeD3>Fd5jPde8_~=7O~z=H>*w52CyZxt{9-odnn6dmrqn zr!MpQ;I(|3Z+{=WQD#xD0e!Gn+U!)^O9j?_yPU-4Ff1mrZsj)c8-;dpkS)Y^aiA>) zcX7ZiMYja7JRf5}T}XIeKe_B`1zjq+_Pgce)`7m5)Y?^>VK++bV&Gax>tX;~O6p=j zTS{pGsIs=xXO$-R>iTuBLPqyqFC?VORyucP{$uUBbsoz7?JPZz%3h%?G7@Fm$3<}3 z=}?9G+STD2cTTe}g4_kzfPH9>Lyg-Rn~Pw!fmPxS@fi7YKSVzga>vTt;spgD7fmYY z0_Ap+w1bII0LNmWMs9 zt}~rjc5cPIp$p1m^(tV;3Vbqe0rY)B107dPB9tcAP}R0z?(|MXBD4b{7?B+?!#*WD zfX!eS?tmEza5CEgA*2(u13v1%`|8VfSGiWif7ywo0=4=`8Q3a)W96riT^~~tB+`?( zt(_bfqCYLSb&Is=y-`R;u7gzZpl9;nu-=E1j4qGE&GWt2*_`U|xeq#mH|49qtS$N8 zD9DU#UVz6kFo#?HB~SJr58ex*)p1c-tPY41upQ;9$En~iK&3jOtp@+ph+zzAEA%D ze9**l;;^$~6)X=!n{U(B3`QpvJD$R5f^-fOAp~;Ac+NPQfr-pI=F1W$lSxbHY|eZh zDzUl~j0w}zPS*JxRZ8B{K*!K8pU2CfCvhC28HzXzWh+>obmat)4JbFasyPDGzh@_@ zE{}P0E%r&UujT6SaBp-Rnq!rYs+a`K#3sr@3P_t}g-$ig zya;h&7vgBrgF)b-h*OMYG@F=~5cfTSfO!v?Pvuun0c=@k!8P!0n-GnpiK%CU;{qMx*;;5g8ywf+*Lg87U@X*!l_fJs&v059 z5o@u9S<=i>>9rGQTHo_+vcxHs*j&QQ3N!A!xh+yi>l%@QsY7Iwud(IRfG&nIpAobQ z?^q?D)a&MQt^ue^>2#Bif~6q zhgJ1uA-$T6zrg&J?2dFw)^#eUD*wF8e+sA|>9Ut5S+NiAhK%^IG+?weBP!9pXGkU( z4mqL`P{?|-PhV=xG?zB&5duGnU) z)=o!|$6OzNs!A?HUM*$06bTllN^%$ukS{}egTTh7pWC+~=*4S2Uhsp^ea^<6K~ae3 z6|;xVM4p`?2ifK4+56n9ft8Fs-8In#(o2cVISK2Ib;?~l(otvUg5d-0sOF$s@w2)-jb_yYi=`3nbmj>ojCC zmNYwVY|fb~hFk7$8+5uPbOF{!yAMb(jFDfh{Y-(yRGqGs%?`$)D^-P=c-otsWiDv_ z)r&RAYz3iSXsuMWO12AS*|22WF=Ap_C69DKL%QC2&%D0+W(a%zTHGyZLM-<$PCrW9 zF$5)JEo*MBjt;pwVR}} zgTrVJRBVR>Iur_ zu!do1)5faFQs5ULPL8UxNKy57d7H^Un$8Hs^;m zu-f~JOUym}thXt6EM3NV)}%C*v8Qso#I(paod$+7PZY==NEf+I%soXg2!)pFZPfx-7MgprS^a-yCS7=V#}1blVX{x}s*IV>;( zx93*P+x2$0Aj&f&c#;IWg$0^h@YSw!Hpn&dY|y@iLw(7w{nD+)Kw`uOJ_B5C=p^}5?2rAJMo137jwW&(;z}{|G z{kPlOKdh25r*5@LV@Vr@QfGrxX~pIyEt6iMowm!MwLs03VVG_u57lpXZ`qpib-f*# zuw;ZlM`-qrm>W9BQU=ck>DW3OTMu`H<-w4j$izr`2&D%%vU`20O4Mk=y5yD?3D&DH z?lI*F3_Tn(xrM1;2toRYT{|qtA7>_O$y0UKUksSkm2J)z7xM&^bn0c4rizGkjt zapzC!9qjJbG)Tj=X2lE6Ww;-A&qm*QpjFbu^Dl?Zwy;uzD zaAyNlUk8OF5TJWIV~sk=CXDUD&vG!B&F;Ltt%kHBpe2tPClpSQvTQ}y4b=l3Fi??! zL<+DYQ9`{3XpAEi>;N06lCS@;AN{9QNBd$sUZ<>Dr?Uedrr4jFE8ZCh=Auu0l`Bf< zF3YugHU>$gsQ_En@z`xKC23Sq5{5e9u z?*lPS{xaOrm&sAlVHu=%Kb`J~*Wmwvs~AN?4*k1rr`IfET6Uc>W-ds8RL>nLH>`M& z@3-RMw<;T*?SX3qgI_4-=qmEtXdIb#-WHl`HG?;!7d89fuQJ7aV>@eBe9{hb)n>cp zosB^IXU?-=uM)7K>vU;gjEN#k!^yJSS8P>js&Jt8!G+LbraWizQql6*r0vWkD0us- zyofN4`(QQ~CbVk+I8kLy4HE-jnX~4Ay6AqX4x9}N`6nw}JO38BpeC1VB%Y~k*xB*T zb%uVVE#pc;eSz1b25({h=ZZc_UP@j4mRg&-1&bkLh@LG{lJrSdHNZ6ghFOzJ&4=vJ z&ywVcDRk&VLE+DNdPZmp?=hijp0zF?RyR4Lv1xvpkEwj7F4OjD{~+EECuw`Dxt9XH_ zeQjp`Zc*z(&60blVUS(n>Ez{CSx;nUeip)eRF;rmRIkQnU*Bon7+S{;mYrVD>gMx< zI7r&(J1-)8NqwGY<$7`^W}JTNtcjKFSySr7vX(U`PpqVBT^STxkX4aG(IM?A6Dc}~ zzk+Ov84I6#K1GMKOD9z<<40RG>&mTIgJOjQi#1SJ%CcAkcjZ)zHL(Bi`4)3F#nMR^ z7nA76%Dq^JWR(Prb#Pb9!dM4+^;C>?(Es@P7@gKHnUrxcxqgh?jMWI1PtaHmbCoQO z)lgSW)mRPr51+5mwIQEAX=4fgr_S71Lc-IfZ_F77O*tG(^u?oQakSUnUr8Rv+@$jy zk~x->oMv>ae*H|-I#x93CAZ^OmD|zjr4n&T(w9gd=`NZV%pqCZ z`id-)u5hx`1MO{&f*na8(8V#y}Vb*Uu_=qocOI;{Nn%`jQ) zuevmoIi|fNnk?CE|B6#hy0Jga`6lZd_S6|Co2bvFoy-ycbtRr`YD+QuWNCB0-u#p9 z?ADZoGG{=&q@gTHLs<}+Hn}L*#n`oFqjXx)G9~5XNXODiDRWJD$xOL?W=hxkSSmeb zy|vhwpwiu@eYRODU71`oRi$gzJ)2~ePNN$#R%T6Xm$R}Cc4gwqawLD`)Ro0Z)x1OTs5g>IU8TnS{BnMa$6Q) zK30OuBBCeCa#`C#o$9iIxW~_TS=5!QB)zOvj9+isOLxKb)VVKfu)ie0`~nFu+xEwo z%Ys=auP>=E|46A28&Y953BpT0%s+w8`E9otu;Yr zDd=aEC9{JwsCQvMZZ#jK`zq12c;iF-+o`Er~nNA(Lm8^KktcG&7yOOb*S(sr)(;X)Z_i zm&>O4J@oIA*bbzUTbwf1S(U&ueGpj=cZ%;Z3_(aH*oPqql35IVN}^xM$Z*l*z3ir- zbllMlIlG{d9=&rgNg#z0M~I~`5_KSOLg6ffgBgej2N19b#%xMB5O@L^WhG?p0n(s1 zg8rTOB2zWoBRU5o*+vOw#W5;c>itSathb?ny4gWBqTF~9?Q!^(;}hsmG)Y28!?~Dz z3&TRQH$RRwGW|A zzcRUisyj{P0vadb0%TNI(#CkzYn2M4jvNlDumVoRaur7?3wo`jrM!kVEKA=t3k2t( zE_*cQi2i^h%%=LFc!lJZ*HD63{;rt}iew8KWzs1pK{`+R;40GDuj=tNC;S)`O30b^ zn3Cwf$f&1u`NBw+&IGa;nx(UWEQn^&j37%ftC$r;cY*|1l@_GT71Ep72$xPbvQ+EVopNLuA|55}$TEa1nR;ZoVY-&|BTczS%GG#9{*m$wBo#SG zDzlJO|GLqEfB&qF7l>uFJQ^^!%UUMQiqx(ih`=@Th-UvrM zHcfwfe)_c&PdX& zo9i(=vJk%}DGQp(YD0;$`9DyRQqDeA6;bNer{aZA->J>fkVNQqJ0rv1 zJ0ARe3}y-A7LUOUMu|MGr4u*jq5(!EiHaRj8iCNF)kdTDzRF z-9CLo$D0N_8}@BlYFWJkb>7mg4Yq29AqyIk|70OHS=fz^6tZwRQ9lxHPb~*p^HK-= z3|j>ISm+yLdWs^J3+$0le!vj|Jdqb^2{8AW{=G34M;=gFnM|Y_8(daBi)c8~hbMna zkl@2TqG_T5PSi$YfT*N(gd=G@ZpjoRRDQWgi(Gd+LW+v~n%}ld ztFltGqj0s%6fNmeB-tD4dJBJm=nSiaZ|>&$hA4fOOQevM=!@5i7z;!nsNDfc8hMbH zxJ7~9meB)0&WB}ev2CRTVuB+sesKa`W!@;gP4EhkNM!^POJqS|5xuj^U3i^09Njb# zDs(~Z9kGQPke+nU?}*pYB7-cu6iqPWbPoQmXVN~nK7DsKyt)3{hs&dj(|_i=Km+n( ztJ@?bU?8;nR#)k&$}F?A9HggEyX)}?iuUN7JTb-hPsV+&2G zNySX3u7U~>W*~KaSaE`CZk0$`cbtTwEbL_Q-2gh9U@kpdj_%rYTe_DZc zsvwE<30SAS*;dWwCOB5-jqUtk!l03x#-?GI)6By`bJpwh`$zN=rp%TVeM_jsjIgOM7 zXUEbllVTi{a$x}PZ*(M{L&peAEYQL zUcXLXi_VT&TTH`PCLAeBQIB5rLVYicuM|+R*N2{O6tK`yR z`I1^Sy~>ePglfDd>0M6ib`ljtA@dgPcK2R)cWsZ+;lYc?=xIDgIf3v=sP<==T(eRV zruTPcuS#4;mZu_9W1bjaNrd@4?fnm?_czBOoUpQmeTFBUtsY=#olwi(=Tn@gt&p>= zQOPHA@7&&h(dLFOzLw?)=+VTB(1WMJ%0N$f;9!g=GIZ0+<|Exyo6fYg@#KR!t!K^G za!0TaI>XcR)8iWubOR`Ja)YCx6wDoPd^9`-zx;T5DIoZe!;nn6Q^-!rR<&(#dOkb_yWsTlL{K2!ei+Tg-1@`y)kOsmAQK-^ z>FbcR3u6;UVC$8!rFUQLfb_?n_+eQ6YP(~5WL%bkESD|%$cc%@QhWK9vOo9^i$ z$`tpy??P^byk4JQBf6DuKyHU&wabs&;aL6N<3>DdxbnEUEsuBGaUy3|%`qt4rMvvuOm`yWCi0@H^7~7Gp#gWP{AE;yNiR`ZtYPl!d)|+c^ zdMQdzqw^HH-lhe_A|NNB2F^ef$%o%KFM&)_(~>DIaN!7Z48s!?!nsKgaHgJtKs*#3 zDxZq(aO$>z9y@n!sr#!|0_bKD1UKsEN+9)3ayL_o*p!3;(1-g0PoFFUR;O*qzz!3A z^FssJ4d6bkQXnNg*9YnxNbFt|wx{-g@);Oa*?jZ+;Efu`Ir`O^i(;!&$uE^%_wDM! zo5Qx4^tzSXz;Be_#X+`^;KhNql;Onzx0K=%z#Aa<^edNRt+z|1*nYRV3_F+>lVH1Q zGwep`T?||c$z2R!OQ~H9XiJGL0Nnu2vz)YMR#2(9YRPOTuX`2pst@tC6}J+o&600f{#pRDccykb^4a?*WXDO^ACo{ZfRZE%JW57cp3k4PYBARW7(T6) zBX*2Co+o23ow&8GbJO8Orj`|Cx~pK>|h@)cG)I`jIr}6 zjBU4nv530Mtn=v;=qjdm>&M3D&stGggkR~a!OT#+AQ9&3-p0xismnABOkFA;hnT~2 zZDvwwBZ@YQ$;nWxv*8!XbxxDjrNONrD&6*$iSgC9Ty$1}!mYr%R8vLx zPf;|FHA9t5+IJ5_aAv+ht`Allj$~O3lz;@~`}WrK=M#zuv$wd+b#P`Xl((y#5I>O- zpwbS3G49TS%`(X~M7D31qSP#3%wKh0UbRlD4OvQN$QCpHQ#Z>YvVGfhvK}k$&)ga( z5ACUl#e|^%Fp`(7?8XzNG*AFWb4%K7@+$KbRq@=M?X?CEju?lLkJ1CHb|R!2R_6>T zP7!hqsFF_DbhcDoT>@GpDz9i3MUrHh^YU7KSKe%v-Xbfb5T)V6OwtLXS8UuCq>@vy z73kIDYm0~r`$-E@a5O4@dXp6G1q43;b;*(9q^%U>rUGFwzC!GtO( z=xWNrzXKTAk@JAw%HL5L0c15XmID+cnF0WGjq)cHbdSZrs1LcRR#%&9MQp5NNi;So z7F3dYr*T!&u3IWU?ZP~Zat6%O6Kf7_-Nc%s;4vrG990Wx=^UAB)zUe-RM>P5p(_Du zoeS>}VA4~kGA3{evCfj=+?K1dcysG=NHf?nJHdowgESyJM8c5#F_|Epd0!wuhm))j z0O(^(`yiftpjnX*A)I{D@V^swXiRa$$Ds3PW+KKqU<*fnm;?xPN{<|LKzCbMrk_C% z9K6}x1^?;hni`AgVQ*$X3d?TYW#}GJY2N!3bL_*=eqS)R(|S$}lhrmUwVytLM(V-m z&rTpM10kGDgxxxt3jl&I-zXLG`Ey5&*bxI1Axvqs?R%p&=EFCztDl8rTeoc~M+tRJYMKVY(4CQ5i zkv_<00Cg){rZ5Mf>~=Y2xl^uHjME&KKbE zhW*!=71lk9ZLEtb(}3ZBEh*%MTNZ}`R4cYo6a~@->97z7`JPnIF0kP1UfCP?u_HsI zOWwVYFc)y&;Z6hp(v9JTY_n@~ko`KXUS%?70ndfNjpeMkw01>z<%q6>CEuwH^TP9b z0jTTO=Du~Ad7)wpbV}J`K}QgFt6ocK*xx<;YefMg5*N7R6!@GQkbazeL0%jW-mi%f zyHy1YBW5{1ETD8O72Ianlu5TWlrnXGqVk+Jt1ImtUTOJaAzsuz$ZiR(q5wx6P4XHo zr9j@Unu7S+rB5fFc-&gUppcT)&0}gZF=r`Qg#~e)PruqU zyBJ6G6EiGRC+Xyq#)If+q!uFYwrE5A|GAwb*Yf{mfo+#pH>blc|H#+lV`}jKy?wj4 zSM>iKy!ii~;&c4t(e(|uJi0jTgHNCI9%WaqYd(M8P;Y-ey&j%jUD^eH7GsY@qRi1? zP*&n7j;%r)fBB2a3Nk_5wkA7Ye%s~^D4kEdX8b@HFU^FWWpJPmMB(-!MlN)<(%&gHDsWm9#9+6c1g z#>QC$2o029#TaSG+}N!{fXxv}4Ocfp=hR8>XOl{QK{^^r(&K#Z^6Sw?*8!L-S0sVZx^x z>Q89Sy3)04DEJA@g{>jI4nM0AvBd@9bnXHuknX-UPr(-Y&0$c=mCp9IJD@zn6#>Dd zC+L4Cbruonv$*P1vsEOzerBOzdRhWMXH>wr$(CInjhW=ESyb zYhoMw|MjX>U0vP%TyMU4QsK`Er6 zF6DG0SDzF?Q%2o(R+PRbeEpX4e%)pf%PsuNE}y-lF>$y1vca@A(-GjTM4 z$nJ;KxN3m%rUk7`twWk=3~L^FjIKr-t)x|UFsL?sGIM6`_7%S=M6!ITKi*2K=LQZO z9iHyKJns%JPL6Ibh7RlmpH8m6x0{^WkAKRXtD3U{PAO(hI_8}Ip?F5s_Zr4o{=yn9yfWHsJvq*?rxI9x%uWAg z+>UXmQW6=$Ym^JMYrY2b8$Q&AZQ&hH<-XIB;ag7xk1HX3MOZz93|(-+O#)R1Ae{Rq&*PSf0Ku=!_Ty6$&4zx298V~YlvODBx;Obm08 zzMt>7P*5~_x| z_V+37o~}->yEX~g{|-177{bGOJq_c`&ac`*=d8${WNHz&>=a4U_wm!Y7Z7m4z_V-u zwDEj%mfOV}-aw`~`j-tUlmJG)&*rld+M6+@*Id>rdz4Rm_V&Qz(GvgU<_|jcL+C|% zzZTn7?2?swO_$SGo0%L893K=BoR^4ZJT9#QN9JJXp3tr!gBYS7L;D$hC z4{7CK_xa8+eG*Qpn}Y~NMuqFKI^L`Gwnd`vX;tSg<{+8!?SeaD}|xwrmH+`k?lx82;^+c!IFbQaY0 zk`BVd7O%~h^81vwnzxkgZznNVxAqq%jf7|9vT)G@zwwtfOchM!MUn3ykgMxa6DYgH zOZ9Ddh&P44fMvF}5MI+zj*3o3+$wq4-nsQ^noJ>m83!bBM%wErNuAo!#BU2o9VJW$ z8ySn16DSv8(L497ASCu#ZauMczQK#G_Jvj>+93Ivt;1uJ?{?OYvlzpjS}AvQKwcU~ zK#nBN(HA02sEPRzzJXa%FeMaHAUd+Q1}4jrmt*}?Ql(>jg^I16yB4rsm;8Nj7QoP| zm>K2~5T~Y>s}rK22_|QEToM_B3wMoEv?Gg}I~z0!kcu2HDM>qSa2qLwu20(lF~x$O znZ*iFE56nja}3}t4Eqyw_;uz9f*#D=uO4LHhn0N85VS$ zBZ19M{q<@ARkzW0boLY5c2@48CvB{-6|#G(o{nT!Hjs0Yut$%~zPMS^RP)j%Rrrfp zSruf=x$p?|NIFs$JMu44#YvPWF$m-F-aj455FYQMW>K-~tV`mIjp>z27bG2pnWF~j zkdn2`R;YfjvrssPH=0XE6>sc)4K1SZsz432u%Wi?wvzuZ+Zpg+`Ki$6UM% zfB5g55)**6%&--aiQ@)#!KLU52>o@wR~j-%Oc&+6?DmFHm{UmOBt*dRCEV`QYEitw z-l!)AD)!K?SSq{m4B@GV@m*hoIFEWhZG4gP53Eb+g~ZB^ze@}DRH>{#ZCE_%!;*bn zlQbgu^otO`8!%D(j?XtUQ#K_fZzZ?KtVF!{v6Rz5c?l%Wpjz$W1Jx{+ULr4SJuCC& zq^O2kn-Q=h$81z^5RifirU?zKao{|!w=r>N*>Thg9dNxG*;@$65MmIGm*zx&;$%4( z9P&0OiJmq7l-n1>!awcjIzdYd1weUD-$~A-0SqEC;wvpM`3d)S#Rc zTGYVP0OPHzg^nC%S3@mY@vWTjCQMq4_twDW>X$nf=0#MZNX?;&Km zRe-}S>8Z6CQ~uhSWv5hrz=VO$2_Z9OY!uf|j9%l!v=d*t*y1r`ZT5Rq`Y|WyYIoN zS4TUgpf=ldP7+eHgpQ+$h6C|Rn) zMGcbb_>8QOB9IH+!AJ41Q_BrTZ>GYkl}PF-l={|5(^)PqIkZ&W<-4ID>!}qOw;HCF z7Iog9wuM?%;JlO8S7wU-+T}wc8?fAO4o+z?exS2^$fX1QhtiukwWYPr&sjhPJE{Dz zGec|&5C`K16Akk?RxE&$>4=6|b;?TsZB9RFb;1MZG15%vF1~9!?~^4#ZeBzd_ny2^ zTo=SDY5zlQ^sg+KZ#Eo9d+M`>s@5XYN#HipGEj7g=c2X>nR>E-~^EU3h@ot&~e zcpJShQ9x@BPCO{)YK^FV#Cz+a`uQD~`TJ|cEuI6P$uKp)cE5&4_|fFxVo3n^K>S<1HUh>OE}6#rKiLzX`ncB0zLayHXy^O!oFCJn9j-J{aQ!(m ztwx92ft+s2KC6nK4S$#Aj-fCE{DZdrmsO>s+Qse;4vnZs>4!)mm=OcHQNbN3?mXED zrz}2tUY8A9dQL!UtxxB1)9$_7gyYFBpHr1#IPd( zQaiHf)|lE^G#OYnEnv6jJf?BxuVu~h&A9&w7NAHZ$=3R2^2z_5VGj~b&|ZACJB=2W&fDmjo7A_#6WFYS0( z0s;PcwkYZ^3O+>#zszkVzkoD%J6}un^t$uuYe$lt020Cg{c1hBBm&n(2;VE_sB$c` z$ysD(E1af)%@0m!EV04NNZIrgmg0gcboAPa6_hjbruE3ryiBT4?}FN+9PIRA(v>mx z>BJM3PMf}2(TDQEPI!iaiYA5MSDQTU*XaUt?K7qK?@!-e-K93}Xd?Y6i!KSK)OcXF z55lDYog1Zu+dS+KOipVGl!9-1H(|&!^qNGb9=D!ThIZ#!g|(&0 znwnhnDK>O-a`O=U4J73gT0qkKhd|~ag)myWdayZts%$;urXQ62>Wr=%p{BjGr`g7j zpWj>$gIwi2*0Zq#oF9T98$SJD#}9{$4iF5@J~5%C%AgcSb;Qo(q)LUbOu2s-_$NxH zV|9O~i)yXlTVYZNPFhedmCUK`Ov5@+YQfehX!PQU5ESlok3@V#;8MB#&ng~p+M0s= zI?<8`0;*jyRG@W}VU_HDRM9A0kWd6UyQn}U1cMwFlXZD{@bNWBowaTDu1(s==IcG@ zBe>npx8M*zL@-P25VFcH(*pfVEKn=bGU#PgE*u8Ty$qXJyDEDcqpYRVH-Q&^MsNCX zN(Pfd8va&_U8ai$x}@C*;#TTcR-CZAtxmg`&LS&zA{dflgpYig_OxHank%O(b-KC6 zz6BX+p{cH2r-pUAO$d;kZnN5`na|^_wyZurrGUpmZR*rWjMRs+A$pB4dOrPu_Tad4Fs`Gt;XJ2r{*ChU7zR`oy;iAKrlEXQjUWL7^kP2u4z+r`@^6Mcr z8q^9SNaSG`6PNAcY0xpeL@I#j?8SGMYw^#IjXg$ed>8n`@8;+e>4PS4yuYyBeEF;}r7v z#R(RDXK|Qvf5>8eJ+~*SFduMF?j&B<|)R10*mRS9d@^w%wsz1rSyjVh2 zErL!rsJ-3)`ezHMz5DHT=kW81>Vo^=B=p#TPG=K zKAa`RjYgavmJ3*3+99#Y#)#r9HIBJKY`wBby-BKfhg@Ae6wM2?USqBjpP9)>x|j#h zz9=|+YP8?so&-E;<q7rYz}`?fTIr`#6_=o9$MO@xU+T&Z>cF}l+_y?pk$FbTTp z>~=a|&dWLm1%Gt5yu1k_yKi?*fB-iyTF0RGv01oq+Xhr+w4!FygrRVxu{1TNS)*w( zt%*syT9r!mU`*Va^o!{Fi*zKgCGjXMjE{$~UWV2^J(7W{9bJoK9NIG)lA15QpyhPO zB31rZDEI*EsF{oqPi8{eRrekmE`@^vFfbA=gkP)mfJh5K*TzswfAKc;jPjE~9jB*9 zYFqq5z3M{PSPc%ReSY6G-JFF^3vYph^lfH9e0)9G`chEJn*SW#5uEES=HvEdub;pt zXmWS=Gy3BRGmokkq(ez31%-rEuexVZ2u z8RY)-klg`N@9@I~0j@o>9`u!8i-qMCo1)d)ykyvfQfpS0QW8|Pgrlo=yOiv!tTx%4 z7qjd>RDK&wOq!K`lv?IRwfJ7Y-O8kUxm;)~O8HB5@h?Vk#t46U0Y1%|!&Up;K;*?n$%f4E(letvljm)Sw-2mQLygtciV~KZ-l8hKA+0QRiEz4!;Jh0>?ff9&X1f=!Ie#aO%VU+@yQct?CveCG`wa6 zydzG^F!a4=+ML$I4bQJQ7z-=O)Yftp^Bly2`5cv}^-)ukt2g^@zW{<2djnnXJVgK3 zg!wan=X6g2umL`Gtt;W}&hECtWe0ti_vONU&VVlMO_$gO+N8l&W7R`4Lza(iJ>Qyl z%VN-~RbYVJo1i`N-K)Pl=wkQ(Ug{r+c2mE2Gn|&Dr@Pb6-r?}yQF_>r>TqYKJaZ;C z{AdIbIYAZjNzjdjKF=Fo-f$U8Tz`n8=rjyI81p~~7;)^d(aCOD)*=3HI&Gfth>lN3H5PcZu}tfGQ!lpp<>=3?R; znHktqqQHLu4uzIHdud2^H47A!*YG{J@9htP;gx!hpinf>Jsbw3x}D+yY$J}JMp}8_ zr8nnBAdpf?A2o<4YDs3N9FkO|vi6qMlM`aG^-9PWFtA#$tyK-pmHhjasF#jTZx;Qd1a~_vvoSQu6;id=y{Jzd&OCDFVr!PnF(ke=Avvbbc_5Rzp zl7|-Q*hdIF1`NAHD|lUk?ov+2E7jSz2QGsZw%aZrOY#!G&r%CQ(w^9x?l(^msP`;5 z{R2ex;?w%Pol)5E?JhYCbw{|aNgUi7&L0lyGpc0s0U82Z?40sD*Hif-$ScoZoNNM4 z*NbK)AB2K}aHH?--OhB=4Y+-I-Scmn(X}W5e#4q)jVzK{rou!kck+4xV?{b(Sqc~; zVpM!aVu<=}GOH2z{!&ef&}%ns#0u09QM;e2F`>vT>B-P{Wzjg~Aat*3CrC0Hy8L)x zSfr(9wZKkjdSG0t7q4#97#Bqm6Owfp$kpwh+i7(pj3bZx*V!3w_Pg=q-sqyjwzH(` zmL_Hv={IT8b!GkCUnC(chqOOYWUK33SsJ|5OZ`~kt_YP_bp`fnc3ECNx=THMz+p?X z#2^Xl^AypLBlo__a9au>W|#jEWIg z*?7y1ATZwy0M(EOF>8)x2!=#2$`P zteCvz#>HOS(oc?==Jd62gE%&Owl@yC*A(R$@R4$SF2?^9>QMTsMkb`11Taal*e7wq!gQRUk4M2>L-IVU)J)E2P3{;y}q$0PsOY&k$D^tyUJIo~}Kf)e= z{`(er8n8X70V1rW+3^1eqik6F)&z~Ook>?Y^Y8Xtf4sTtD;E8_I-_Q{lu9}Wy>0c* zA%>e}SyrOT`fUFz$S~%8quyz-lNk0ET}GQ*gB3*A?)&WE3^<~P)-+|TN-w-e8W z@tRvxUR5Ty0+n<7?4|0RpUkDDd13};fW-iH#a(-F;NOmAqEWn@R#vXu@4Wd%(XMN9 zUGmf))%?%JeLEhTDcU5&$*&PmWgI7k4j30de~EdhV?yPA)z?&Cktf+8o5Va-8!JL> z!=u1#-c2=s(F{!4-ld8y zEmqUQ)AmuMS(wVQB&M5%C$O+EnQ_3^j0K|s!5fPMUz9N^NDJ*;j~!|3T8ws8#Ls?< zyM&R`{JNsPp9NE-ufd>FG^ZG&K2#aagR=xYeFI1v8wA^>u*ui&`uuJTcHexg2ONf7^jAd@^B8Xk2-0 zMkuH!S)q+anz}Tm6;-c2k=1oGFQ6UI_OOvhX7!et^V8GFtzI!v;96gT6^J~(t?+(} z^R}c}#@!VosF&VleOovn!nB702F%9J?;Vyl(1xja0n)X3+Pi>L3~8#>UD13T%r`iq zWq2VhC1mIY@(e65y*XW%L+Ikcq$&Lx?(tqHmd$e42oT_rdXAnz+>&ph`tN)&o1l#%wL?Y@D)fF`%j9T9be+gX3oI2ZUvMOCY(=)34%%|~5$odvvhr(_2faB#^ zoC-dcwfLzfM~3 zdVfQHM}7~1WCA0c0pIcfHM=00H2qLTJ-l$tm18_bA7RkCe{t@P`Lm~GII;ERzumbz zR$Wg>$GyqigwB9q(t~mXSQM7{LTmQ6-t9gM+y9^s8K;{4o8`j+-KDC$!}iBNrpN%z zp(h)z3iXa=1#%0~k9}Lv)KfgoGLeeb%V;cdY4)#i;(5n;{eK}Ek6}*&^dZny28H6x z7kKpd(ToM_k&vW9^iYXcxN1`rY$Uof?a7mcY$RN4VxsTVs}-sc&u~ZD>heYK`X2?G zjg-qHYjcDJmhyA-1UJKg)s5Q1Bs+k{N=8AiDnDJXNTtuO51C1~F$uT&u1}?gU)g1f z(XHrWO?DQ2pplYf`kkrG$tHsV%eGpk4eHIRL?zg=a$T`9`)4hF`Nc*+L5WT}xQz*Ac9X)8!# zxJeumcv$jRUh)G0T_whUpH9QFg)LmNU#E;_jY`=h8KTKA>kj94#+A`#ty;-==m;Jc z<8Ec93hX0ojQFf?YwXR(>g3_<;A(jC{MB~%xTUvLOxqjG?6MntFPpJP7X&A zu*HK`p}E$ZwyGp$!<|ZkQ)2SI_(Cv{;J1O6gmNTHJzN~RfEXHfT7Z;&jx}t70m8>o zPN5W4_0-Rmr0H2Z%&t54PYk{bNyqR~r z*l7D~<1^I{;hnONudgGXZx%U+Es5uIm9_ZHiun zMg)P5ubmT8+f#^jzWKdn1OBA4cW<8f&{wV)@C-ibHzWR;R9APo}t5x zX4e-`vYz$hrm!{d)eW`Hm6Oo3Yg68LZyr{6#2F;CB9#zC$655xazo3i^_v#2w@9=R zrty&?3TPF!tE0)eOZ+?Vwi@l?dMo`wk~sDUc|#2m?v)Um0W;FBS|>O>g4}rQo^$d{ z@m+#~9}3i3R>G5LX94n}tot;G1{)?Uhi!A^N|uH^#Ta-;#5>>hglEf8u4<;~@Q*NX z$jpkhzhqujtwv@4A?S_5CrX}7vQoujoDt!_YrV17CS^&N`@{fk3tF)jL9xT+4bb#f zyBkLmd3533YPaz4qBFi%ZJ^g>KY!DcD}GxP@2?kw3bV)Z%+N#G)ujY^QyFP$cebaN z?PB$kTgw;lP)qBF)4t4db!tqssBdBm1YRa`<3XoR&n&_1JU|1JNf9b&B}z#qfFJiq zJGlZ4-mX1D@WUO`6o0KpqbSOrjfbyK9m#2Q@a~P+O(rqVled>+hiEs~J;KM{%u~NK zM8PGD<)UlBUXvkjd;0^ixO@B5^N-_4muUhcc?PyC)$4Bmxz=;Pj!PX~RprWCSCel_ z_D)FLrKU_gIm&!7*eg_46x}($br%(;*Xm*%dK6DA{1olglukOpJjqlhjp;^J`J|wtvt)GL0p7#_#&n`elE{chO6;>eiy(``)dC}~&E#>Q*P&>q zyY8q!`M;AIDp04i#3I$xhLcCct=%y;L4NH4i3W7o)SU5|N-Rms+_>t(qRZ0g=;X`AlhWuHiOWAV)u~i& zb(e8~H<<^Im`u*@`5+>tWr2RuQyP{L+YIwkY^rKuHBBbET#96vnrqAtabfipz1-h< z?|A@hgdN$rUc4dvSW2h7#JXtCq425W{dqbTo8eil$(jbrQo#y!g7t8njz+l1O!-ypG$kPoMY;qZK``-6HPZ_aKzHiDH45@;`8}C)W|b;qy8QstE;FyHo+8Cnaf&XUh?oaL z{aBh%anb&{ZuOz+dU^7ar*?veRWMEUyE?NB(19D zMwRnAZBB!M|1;^-nQ(Tv(I!Tw-_;A;qrEuz#crq|RHu=Y*S@f972%%394L#i8z8*+*7z}EFY^`O9r z#clCUtHvrPfSIm+kcu@VL>yP_|M7Zz+E#TR*RG{2swHr*=2`v#7(wy0g+bt)aLFiphB$oXvkfeY6{t}Drc!cLt2F1#u&5e z;eHC49OC}|KPAIh=a5oa9}-W@G-sYP<6uvP0ylQ3(-^^$g;LPMts~-^34(D|9o5qu zm3L3Isp*fM3rf*V?+W!Zr%<5Uagat@&zjzH0QmMWy2jR%+hNt13RY4>yXN}tZ-+Us&u6pVll0kvn9moL;c|1MFq}sJP zO2y!Dw|XD9m=m<;PUc++b=S5sZVbUE`X(p2i#!t!Chi}qOdtJP0pIICE4lnrh)0AS z97|iH~3UWSRpMeH4TL_OsrW{cBg|NFq+t zn_j#)u={ySna;x5ak%X8`@x5F{3Qvf&I2=CoNZp@Dk)pbcd`>mWDED;z=^1SE7yY6 zSgCoIPRtt1L?sfydc4+=I-yDNn+|z;T|vC%&D@Mu{mcOgQ``|X#46Gqd)=%l>jMsOHZ3hm`Rln~`zdcl@9cW=+Mc^Y2s70c-x}1|3tGR{=q(;|pk32vj2T!+HcG9uOLI|}j zrf7kQKS%!y2$9%%R1g8dgny#_OLg5~#?KTXcFHK+fS0-0*@Wm%a43Ty(%`5XK65;% zI&F|Pcdh+1W9f>~LkiE@pafVFB;A~MayCr7NJHUAVR4i9Ns&RRp&w~7kOP`MdCM39 zGG&IH0p{$tz$IwNJqH}hW1OA>JUI`c#D05<%l$F zow}2J+JetXTWV{zt>Bi_O`Tw@X)!~m&2F;!+{h!SFeehH?vV!;vBvOA z%&P|N8V;cu6jbFn^6>{p2M34i#|P_|tKMFr&+YW9ErR!x>xXssD`Y*wF5kCT04x)V z9&y(j2A9T@$++~yR|bGbqqXM!;OC!j?35;(KuGbgTX!~iX(b=cUvN6^QWI5`!7TB@+7 z!w9c=VW%SBxJ7S0-^7UrD^(MUU+$ezF@Qwm0^yEJ=JNEp+^ZDgukdN9xs+{MYEAai zq^ROqWsfAA#OQL^k6vo4?Ew){kpVPoVkwbt=2yUrjKWb}3Gc38RU zSc`shG#-de5;KC?c|DPwg8OZWouH61@E(L~PN++R5pYBZRJ1&B0tf-2{Ap5&BCdbr z$XwtU9?=8NvR|IiC>#+)(HrI-n;;)%GL_~ZR;(VuV7Q~*aCs!~UMI2YtI%y?q&S6W z1@)7w@t9KHD>f+1^eZVI)a%Nd=**(O2%HA;2w*t(^r1QCw4H}vk&K$@o9gsPVt6KPdKK@aC3*d#Qb&oq+w@BGT#@s7 zABYuek_Xn|+&`RJSAV8C=&?;SMvtMXshUQ>i7(;CIz+roeDlc+Z}Lt5S=;w51-jdX z;B?W;#p$7wH+l2QPYF!3;UW%$qb1_5@NLR=KeP>!w>r@mFw#*oSXnPV_rs=r6XLDH z2GNjUCBG4~+F3yzZ}Sipn{S@Cpk(nC0`}u#*Kx3azuCs8oC}mpvxkAnh6ih5iq*sS z0qV_8Z@mMxFV`Tq9D|0bQG7o2`{ZcFx?}=<(%i$UWHXXborN8_?7TzB$WG4u3XT4m z;$;?D&OoVIp&!xU$UYCEi}mM3h8*I-jRplZ-Q-101&evk;$cz>ViF>z?Ff}~>d5z% zFAqll<+k$iwsa#pFx1l)((QAco zZKrs?f59QwI8ZmY&xhMMh`5N42((QjIv$9YQs7j}#aUN2xhI+P&y{HOKy%5-h=FS?dc*Lwsnv^w0Tg5yUTd}|!?p3= z<7bg)VKp;_pp36!a?6k**GEp0KWRL-}PnH8^v@G39q$a~H{Uy>YTg(E9 z$^=A#{R4xx@ZE%gU*fn9uX!+o0Tb^ttEr9JPKuCmd>gi**@XZjI$XYJr7_Up*wyi+ zhWzdvYcIj4|MQXQS3mIadAykYPe&kwYT9BbP%qHMz#mEGWxE`(R&*3-T`46QS<;+6 z&x}-%b01<4PQ8_uW~48rZ9{aJk4+fN{u<5&YZ^F3QxCFc8F2AHJXIZbLQU4PmTCBT zce>@^kD&lhy4CP1AnSt_<_ zQiIFABu860zAyxa7?!?L?@EUR3Pj0N(E{IRI8%NJI%EPs>h2J~y+Ox|LR+6tM~6U$ z5C53kj}uS@X4g{oGm7~3rj2D)<-yf~O^)b=kF5EAn>^>->PnZa$}x9Fo=5Sqfu`uP z6JXfsX@ooVsP!s!Ks~0y=zdM!o08PacDYlh;p}N{jNtKiC@^hfP9}nD@m)}5%+b_D zQwk!(9d!KA-th^@0c&{&v5f6s`%`_l5BUHdCSQ;C{I;u|un@MP4{5_N~JXPc+i%xDaNMszL zb^}9B-gu!>>j3YUHAVZsyi$>I`5%cqX&FjMKTcsLAA3-o5LUSh)o?T*IA)tEk)(VU z`BO`L=mw`K1DDAC4zJThf?R)9+Nq#`H+mZGoY@CYlK;`N@xUy!eboxFN(a4kPTQSP zFCK$Nh^t58Ji0zXx&oiWUzqITuQ5kbz;KffP0yWp=jc2hn!8%t3p59J)$5i&tdGhxVk-VZ5DT>DNf}WyXkedKY&Fpz31CbzTvg%z%#14 z>VOPV_$L7s&R2BI@bKF~+m*mc)ZVtZ+;gw~c5qEKYQq!ZND-%ij!%rDxxT`Ls2#Da zFqcw7EK$daAdaCaZe)W=RDVg(c7Jeiy5|e%dUHK}{TURm^gACk zjS|J+Zx&(pC${pLkWG{!(Hku^KXw&MONh?vO%4A!h2o7;C!LMWAG7;#jEHl>Qu9h) zt!ian-$jbR$=M@;z(X%f%DX7#=)P<|cPJ5s`_vhp8_(MQ-+9Aa&76boEOHy zX01mS%J%|$Ss)$PO1l*AW+JCk4~lKFSM3LzNg3=56nk<9237%8R{I>4o9L*@`I+tv zrpH1Gc+a7DH>?eWewXL?o@G@-AHldRw8HX9dcv7;D}7@ttebRK+slbTtDm5--lamb z3D?%?Q92i)70lcXU$4rMInT6zZUIuJ=HZ+iU>E0Mk3``lF4O5RBe^3BmGZ2Y;QTUH ztB@gwc_mQQ6LYGOnKZ^70ugtNARsv$DE3r+USTx)+5hn?FI41cDk-GYb>C8MAHd^C z;Iqe`gA1siAGoX}{8L@nf$+{APm(9*%B$D1S`7BOdcz*(lt!AU*pb)JnCy_ z!5??YCTu^k^%kE4Ra)w2EHXHS{0K<0Y{~EbdSR}vLF=y!UW3ijAXCQq=Ff=mi`K>b zk`mq?3T>ONkT_j=HKNOe89ArLq|rk(SVj5z@Ja9=sZ#+?vdsHO{wSXBrHaBeIdl-cNtR<{aaT))uq3D^(`(oqHxh{Md&T1;f zeJ{;=m5s7$Qc-BE^^y9M3`c!g=hdLucGgdi3sBAFsqi<#0g4ZOQj4fCM^o>gl3ooj zJmy=1D(i9JA5zlibd#kDiy}hGy!5xJW!t|L;qJ}SS!>?a)wH&~=oEV2B@B`}LM-HY z#e)!}BC?wL$LwDZTzQjh|9&%QwR1n7B=ZOT`l0zC^-P{#KFuNqrUh;yx6H*N;xtyf#q&Nn|jeEU`?@y3_Vf7}2#$n}VpsHrag&rKovXq4J z$EZ?OJx$+gthNm8K%Y;FhdWWnh=lnB?{C}InMy>NqM2LI89{1|4zO=QKPDRzN8mH_ zYd4+0#DEd~5d#I=P)|F=+vz@F*GO|LkPH>>PG?SxERH2e zrm_C8(z|Up*7_QJ1tdTf+s-9QkEct*m8aPYfo$3I^C1(FOGD9X22-{C!j_Y*ZQ=fq1fQB&;xhO*PweogfrExO^>be>=;B=1Luaf9~XrA6ZYYqL}^VS3Q7O45lSJloBn7q6F&x)CB}!{cub95s);4C8lU=}>ihoXI{{ra zoNbkk1J9zTj|KB|)Q}lneXFA!j<>ec0p@wrfa-X_vHLLzwd(yDEu*Tm&S;O|e|0iv zi7eqg94C($%gr9?fpqMAj5|2^)-DI-pSZ$@V%~4?@_jp5?FJH2&5viB+zNp#c@{Az zCvNwnHg;7R1wGWDY6cx=sesSq z?ad&{6K+a_E4tNJ5xA{J_>V$~u!|wx)L6JhiVwEj>7J^71T|FZ+Rao}hoXaV8SV1b zx=c+8d|bR9bhtlkHzm*vi0Bkdo6rb6S$|9Eq}h<{Q+S_}_{@sb@H0_v4KbC(QS?iK-DaNmrcRZBTIj6TnO{DV8>y@-Ot`u{4EO+!`O*HUt|?F57O%XTIwVo?pO-qCrlAOz97k|)UCMJ8;A#E$ z?&Ic^3#z}bWhnfg!pI5iZ4&b2)mb%AZ)ydBv3t20-rqS;KrD6K{GcvTmtKonRp53x5;@#0MMSpMq-{aLW-;Fr%4YT z7m7?Wo(k)>D(9;;&fRpExV;Ck(k@bu8$fEn!69a$D^B-2@v~#ioY$!dX--_Sz1TnP_eVbHl zV}(6&m-UD%`GH_V5I40YEfc*mKK{XGcY=U808OAp&=M3um(Q|*1#u&abM;{yK418r zwKhaFs2T=P7l491Uvgp9DWAck`1G=Hi@05g%AzLB2>G_Sc4FGR?}|1tkugqlgjb>} z!Ww+u*v!t>ZrCDv7Z`DrW+p&1*&#YJj3t_EwpEpDb=0PZy*d%smSb0KY{n6id}Q`G zKy8lDsKCu#6-S>TUkVgYL~3z+UP8mi7M{I$*ubheUIORrAwQVx0Q03d2s=E4|FDbA z7Fgb@5(%Nk4K+BKmnYqCXkKp#%)LSn!h-MN2^EeDFfmaT9=H4GxU13kr zVk*RHHF+nNScjiihmn%fcYo-hM$FE@899SwfzjKDV+%U>VG5+NZ}Y7L?Ei5KZy~^? zk!-#AZJDc{?5F+EI~Kck*6RPF3aUx|nS~hXp9XU}1kd3S1cw}s=5#}&?-p!=74 zZ>Nu!+s3&dOP|jq$h+CRj}W#GY~$XP=YO5?nLV&4kLrW~vSZJtGneCD)s;G`g|quN z{N0CKVwY8qyo&X`Ir;5kYK`L`XO-aHW=b7 zu-u_Ee1ysoI+8maqwebl#|$_8(C$YkK(lOo$}FZ=M@@Ka#60>V4(+<97^*MuNa-hW zngs<`Onq(cD{&F2c@$4lRprb~yuQ@;KT<&>oypj~lJLOw|1A~xK)x$)168NOF%B2? zLI$@q*I+lQP2`{1YR!?BEh`DbuAP_IBR(3Ht1R?1#^QwGn>yzNHU4sKdH&~xS1)%78sBhz7Zh%#ZxnB&_QP(Jvq=x zi+@T%3*~fbd4#54)4)JK7YVR&z62T6wsP5+o}8P+9A2hxJbYK?J_^nDcl{N@@k9H3 zM8dquhlndLrTEn_f8wP0j3(UFI@Tw@;O`U2_##-8THn1mMCM@toMF6QgPs8kMR4tD%id5%jM;~_p>Z`$lYGQ@AF3>_$Nd2{}2cwc-y{}i=+#&Mh>AN`ISL@<7A%uEzep6DWLjG zJO=v7j3Rc3`?k-XW50KP58=aLS>;4-NB@5+1c%S0N}h#(@^`?Tk8ab6=bMS!C0sS+ zW|dG{lC-z*33)bFz{1!L{sldZICdi2-Jd?q@g{rkEnc(h08-EqzjVD-iL7& zj#czBakf#|L57i{SS+8y={8(&D+Vp`QIdYsrqe-EvO$FZQ3L2HABYovj-CCh2k zmw=R%Ycp_L6|#hGWnsc7%ehY`IWS1uwlZ(rQ@7mhS{dmpos9e2>-YGkC4KMUcXMw| z`o}4LLEY&S$?dWvenuARDKb~4G{R_&h$mgEA^l5T@T8~PSDkcEc|Cpv8&Suq>5i@C z>r=Xq7Wg*D?4K7_8P#>KbQSa=1!ixpd==`d2*(6DR)(#X`rM? zSwyZ-w^j*RMI6W|<}XpE9DfS}wBN%<-7&N{W2|)+TusI@8|wdIx;`y3(3H01ZUy&U zkkw?*WJIvR)K(+I5J|g2bgGA?PTfLYzc2z$SyFRvSkbLkn4J426|nyO{%!g7`hC2= z|8MK{d!{P5=JQl>@-X`wb&xqkZ?g!h(mCY!j(#GLDZ&?f6q|aiA=t66v5l4_jm4K% z9p3!qc+z(mHJDRA8YMZzhOXTZ!b`g4;bf>z-|LLE5dw2W&UDj1f)8zm3q2mE?D( zDfrk@A_M8I5{C7f`ok5Ejn*M#ZVjEJ=j65-^dpQnT@Crk>k7NJ@9=knL6WyOXtJbL zI1o4IP3(Jh>ro3Qr|&~c^O&EGg`!mpb+5Xte6oaNvam^tRu<-uaLV_y)|0`^EUN-4 z<-C32yNmQ;r2FFmK70+g# zX{4UJF9kOx_?>`^<+O~^h+()u%*S%{m{C3ZunfLP zlGI1w;ep}`HyNzeeraP=Cs ze}?5^QQKZdcYjDmQ=@r);0@CDXjADL1LY_Og$a431rh?vW3^Uld%6eF75wtrHI+mN z#V~cp3(X%z!`tF`LR0+A=HrcDRbCt)&I!Mzk(bgBWJJ=?7{%YA0dZf`UwQmd-`CoT zQm}ZG0;1ItCkQ z8cOzPA@)b#l}ASVF5kj1deCkRUvMf|_U7U;>xf&qBU&i6GP}iA#wk8I5VwcnC&kZT znJ&ecIg~Sb7dt4!GXaw)+4Z9cA*`@sR@5)~nEWwuoWpB;UcY*T>(&J=4*JMS5`v^- zBv!LIZ^Pg0fL~ELR~AJAqaY1@-fm+YJCicH2%>W;&W1MzeN?N(VhYja6N>_ehb7R*|A;l`@qdqYnlOZw)Khqxw41SELyk$;}?NVLmp^IYBC@fvr+0 z*>?*CW%_}m1f^D*OTi@W>-FADSNHdBRn5n<#4-4p;4Csc)*e{-iu%*IVKgW~xG|F8 zHAF13HHTh66||Xv{(xbCtO8Piqd=H|-pTO32ciO+K&*X&%(@Y8c)_j*un?;n*Dp8X zNU;~3y8*lt)Ej=c%{^tzX&`7*Ste2>A{Y?dLboE{t-dQ~A;m-Rvq@QqUYGa&v1GOl z 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

%xVd_aT0Bpe15RL%Gf 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 X57)!>hpyiO00960Z3E0@0H_E6!0;oN literal 0 HcmV?d00001 diff --git a/charts/acapy/templates/NOTES.txt b/charts/acapy/templates/NOTES.txt new file mode 100644 index 0000000000..03df6b87cc --- /dev/null +++ b/charts/acapy/templates/NOTES.txt @@ -0,0 +1,27 @@ +CHART NAME: {{ .Chart.Name }} +CHART VERSION: {{ .Chart.Version }} +APP VERSION: {{ .Chart.AppVersion }} + +1. Get the application URL by running these commands: +{{- if contains "LoadBalancer" .Values.service.type }} + + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ include "common.names.fullname" . }}' + + export SERVICE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].port}" services {{ include "common.names.fullname" . }}) + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "common.names.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo "http://${SERVICE_IP}:${SERVICE_PORT}" + +{{- else if contains "ClusterIP" .Values.service.type }} + + export SERVICE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].port}" services {{ include "common.names.fullname" . }}) + kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ include "common.names.fullname" . }} ${SERVICE_PORT}:${SERVICE_PORT} & + echo "http://127.0.0.1:${SERVICE_PORT}" + +{{- else if contains "NodePort" .Values.service.type }} + + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "common.names.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo "http://${NODE_IP}:${NODE_PORT}" + +{{- end }} diff --git a/charts/acapy/templates/_helpers.tpl b/charts/acapy/templates/_helpers.tpl new file mode 100644 index 0000000000..e02521fc59 --- /dev/null +++ b/charts/acapy/templates/_helpers.tpl @@ -0,0 +1,155 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "acapy.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create URL based on hostname and TLS status +*/}} +{{- define "acapy.agent.url" -}} +{{- if .Values.ingress.agent.tls -}} +{{- printf "https://%s" (include "acapy.host" .) }} +{{- else -}} +{{- printf "http://%s" (include "acapy.host" .) }} +{{- end -}} +{{- end }} + +{{/* +Create Websockets URL based on hostname and TLS status +*/}} +{{- define "acapy.agent.wsUrl" -}} +{{- if .Values.ingress.agent.tls -}} +{{- printf "wss://%s" (include "acapy.host" .) }} +{{- else -}} +{{- printf "ws://%s" (include "acapy.host" .) }} +{{- end -}} +{{- end }} + +{{/* +generate hosts if not overriden +*/}} +{{- define "acapy.host" -}} +{{- if .Values.ingress.agent.enabled -}} + {{ .Values.ingress.agent.hostname }} +{{- else -}} + {{ .Values.agentUrl }} +{{- end -}} +{{- end -}} + +{{/* +Returns a secret if it already in Kubernetes, otherwise it creates +it randomly. + +Usage: +{{ include "getOrGeneratePass" (dict "Namespace" .Release.Namespace "Kind" "Secret" "Name" (include "acapy.databaseSecretName" .) "Key" "postgres-password" "Length" 32) }} + +*/}} +{{- define "getOrGeneratePass" }} +{{- $len := (default 16 .Length) | int -}} +{{- $obj := (lookup "v1" .Kind .Namespace .Name).data -}} +{{- if $obj }} +{{- index $obj .Key -}} +{{- else if (eq (lower .Kind) "secret") -}} +{{- randAlphaNum $len | b64enc -}} +{{- else -}} +{{- randAlphaNum $len -}} +{{- end -}} +{{- end }} + +{{/* +Create a default fully qualified postgresql name. +*/}} +{{- define "acapy.database.secretName" -}} +{{- if .Values.walletStorageCredentials.existingSecret -}} +{{- .Values.walletStorageCredentials.existingSecret -}} +{{- else -}} +{{ printf "%s-postgresql" (include "common.names.fullname" .) }} +{{- end -}} +{{- end -}} + +{{/* +Create a default fully qualified app name for the postgres requirement. +*/}} +{{- define "global.postgresql.fullname" -}} +{{- if .Values.postgresql.fullnameOverride }} +{{- .Values.postgresql.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $postgresContext := dict "Values" .Values.postgresql "Release" .Release "Chart" (dict "Name" "postgresql") -}} +{{ template "postgresql.v1.primary.fullname" $postgresContext }} +{{- end -}} +{{- end -}} + +{{/* +Generate acapy wallet storage config +*/}} +{{- define "acapy.walletStorageConfig" -}} +{{- if .Values.walletStorageConfig.json -}} + {{- .Values.walletStorageConfig.json -}} +{{- else if .Values.walletStorageConfig.url -}} + '{"url":"{{ .Values.walletStorageConfig.url }}","max_connections":"{{ .Values.walletStorageConfig.max_connection | default 10 }}", "wallet_scheme":"{{ .Values.walletStorageConfig.wallet_scheme }}"}' +{{- else if .Values.postgresql.enabled -}} + '{"url":"{{ include "global.postgresql.fullname" . }}:{{ .Values.postgresql.primary.service.ports.postgresql }}","max_connections":"{{ .Values.walletStorageConfig.max_connections }}","wallet_scheme":"{{ .Values.walletStorageConfig.wallet_scheme }}"}' +{{- else -}} + '' +{{ end }} +{{- end -}} + +{{/* +Generate acapy wallet storage credentials +*/}} +{{- define "acapy.walletStorageCredentials" -}} +{{- if .Values.walletStorageCredentials.json -}} + {{- .Values.walletStorageCredentials.json -}} +{{- else if .Values.postgresql.enabled -}} + '{"account":"{{ .Values.postgresql.auth.username }}","password":"$(POSTGRES_PASSWORD)","admin_account":"{{ .Values.walletStorageCredentials.admin_account }}","admin_password":"$(POSTGRES_POSTGRES_PASSWORD)"}' +{{- else -}} + '{"account":"{{ .Values.walletStorageCredentials.account | default "acapy" }}","password":"$(POSTGRES_PASSWORD)","admin_account":"{{ .Values.walletStorageCredentials.admin_account }}","admin_password":"$(POSTGRES_POSTGRES_PASSWORD)"}' +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "acapy.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "acapy.labels" -}} +helm.sh/chart: {{ include "acapy.chart" . }} +{{ include "acapy.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "acapy.selectorLabels" -}} +app.kubernetes.io/name: {{ include "acapy.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Return the proper Docker Image Registry Secret Names +*/}} +{{- define "acapy.imagePullSecrets" -}} +{{- include "common.images.pullSecrets" (dict "images" (list .Values.image) "global" .Values.global) -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "acapy.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "common.names.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/charts/acapy/templates/api-secret.yaml b/charts/acapy/templates/api-secret.yaml new file mode 100644 index 0000000000..34ff48282d --- /dev/null +++ b/charts/acapy/templates/api-secret.yaml @@ -0,0 +1,21 @@ +{{ $secretName := printf "%s-api" (include "common.names.fullname" .) }} +{{ $adminApiKey := include "getOrGeneratePass" (dict "Namespace" .Release.Namespace "Kind" "Secret" "Name" $secretName "Key" "adminApiKey" "Length" 32) }} +{{ $walletKey := include "getOrGeneratePass" (dict "Namespace" .Release.Namespace "Kind" "Secret" "Name" $secretName "Key" "walletKey" "Length" 32) }} +apiVersion: v1 +kind: Secret +metadata: + annotations: + helm.sh/resource-policy: keep + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + name: {{ printf "%s-api" (include "common.names.fullname" .) }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + app.kubernetes.io/component: agent + namespace: {{ .Release.Namespace }} +type: Opaque +data: + {{- if not (index .Values "argfile.yml" "admin-insecure-mode") }} + adminApiKey: {{ $adminApiKey }} + {{- end }} + walletKey: {{ $walletKey }} diff --git a/charts/acapy/templates/configmap.yaml b/charts/acapy/templates/configmap.yaml new file mode 100644 index 0000000000..e3578347c7 --- /dev/null +++ b/charts/acapy/templates/configmap.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-config" (include "common.names.fullname" .) }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + app.kubernetes.io/component: agent0 + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: + argfile.yml: | + label: '{{ include "common.names.fullname" . }}' + {{- include "common.tplvalues.render" ( dict "value" (index .Values "argfile.yml") "context" $) | nindent 4 }} + {{- if index .Values "ledgers.yml" }} + ledgers.yml: | + {{- include "common.tplvalues.render" ( dict "value" (index .Values "ledgers.yml") "context" $) | nindent 4 }} + {{- end }} + {{- if index .Values "plugin-config.yml" }} + plugin-config.yml: | + {{- include "common.tplvalues.render" ( dict "value" (index .Values "plugin-config.yml") "context" $) | nindent 4 }} + {{- end }} diff --git a/charts/acapy/templates/deployment.yaml b/charts/acapy/templates/deployment.yaml new file mode 100644 index 0000000000..50d3c60d27 --- /dev/null +++ b/charts/acapy/templates/deployment.yaml @@ -0,0 +1,210 @@ +apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} +kind: Deployment +metadata: + name: {{ template "common.names.fullname" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + app.kubernetes.io/component: agent + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.podLabels .Values.commonLabels ) "context" . ) }} + selector: + matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} + {{- if .Values.updateStrategy }} + strategy: {{ include "common.tplvalues.render" (dict "value" .Values.updateStrategy "context" $) | nindent 4 }} + {{- end }} + template: + metadata: + annotations: + {{- if not .Values.existingConfigmap }} + checksum/configmap: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- end }} + {{- if .Values.podAnnotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.podAnnotations "context" $) | nindent 8 }} + {{- end }} + labels: {{- include "common.labels.standard" ( dict "customLabels" $podLabels "context" $ ) | nindent 8 }} + app.kubernetes.io/component: agent + spec: + automountServiceAccountToken: {{ .Values.automountServiceAccountToken }} + serviceAccountName: {{ template "acapy.serviceAccountName" . }} + {{- include "acapy.imagePullSecrets" . | nindent 6 -}} + {{- if .Values.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.affinity "context" $) | nindent 2 }} + {{- else }} + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.podLabels .Values.commonLabels ) "context" . ) }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAffinityPreset "customLabels" $podLabels "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset "customLabels" $podLabels "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.nodeAffinityPreset.type "key" .Values.nodeAffinityPreset.key "values" .Values.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.nodeSelector -}} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.nodeSelector "context" $) | nindent 8 -}} + {{- end -}} + {{- if .Values.tolerations -}} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.tolerations "context" $) | nindent 8 }} + {{- end -}} + {{- if .Values.topologySpreadConstraints -}} + topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.topologySpreadConstraints "context" $) | nindent 8 }} + {{- end -}} + {{- if .Values.podSecurityContext.enabled -}} + securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.podSecurityContext "context" $) | nindent 8 }} + {{- end -}} + {{- if .Values.initContainers }} + initContainers: + {{ include "common.tplvalues.render" (dict "value" .Values.initContainers "context" $) }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.containerSecurityContext "context" $) | nindent 12 }} + {{- end }} + image: {{ include "common.images.image" (dict "imageRoot" .Values.image "global" .Values.global) }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + - /bin/bash + - '-c' + args: + - >- + aca-py start + --inbound-transport http '0.0.0.0' {{ .Values.service.ports.http }} + --outbound-transport http + {{- if .Values.websockets.enabled }} + --inbound-transport ws '0.0.0.0' {{ .Values.service.ports.ws }} + --outbound-transport ws + {{- end }} + --admin '0.0.0.0' {{ .Values.service.ports.admin }} + --arg-file '/home/aries/argfile.yml' + {{- if .Values.websockets.enabled }} + --endpoint {{ include "acapy.agent.url" . }} {{ include "acapy.agent.wsUrl" . }} + {{- else }} + --endpoint {{ include "acapy.agent.url" . }} + {{- end }} + {{- if .Values.extraArgs }} + {{ .Values.extraArgs | join " " }} + {{- end }} + env: + - name: ACAPY_ADMIN_API_KEY + valueFrom: + secretKeyRef: + name: {{ printf "%s-api" (include "common.names.fullname" .) }} + key: adminApiKey + optional: true + - name: ACAPY_ENDPOINT + value: {{ include "acapy.agent.url" . }} + - name: ACAPY_WALLET_KEY + valueFrom: + secretKeyRef: + name: {{ printf "%s-api" (include "common.names.fullname" .) }} + key: walletKey + - name: ACAPY_WALLET_SEED + valueFrom: + secretKeyRef: + name: {{ printf "%s-seed" (include "common.names.fullname" .) }} + key: seed + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "acapy.database.secretName" . }} + key: {{ .Values.walletStorageCredentials.secretKeys.userPasswordKey }} + - name: POSTGRES_POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "acapy.database.secretName" . }} + key: {{ .Values.walletStorageCredentials.secretKeys.adminPasswordKey }} + - name: ACAPY_WALLET_STORAGE_CONFIG + value: {{ include "acapy.walletStorageConfig" . }} + - name: ACAPY_WALLET_STORAGE_CREDS + value: {{ include "acapy.walletStorageCredentials" . }} + {{- if .Values.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 6 }} + {{- end }} + {{- if or .Values.extraEnvVarsCM .Values.extraEnvVarsSecret }} + envFrom: + {{- if .Values.extraEnvVarsCM }} + - configMapRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsCM "context" $) }} + {{- end }} + {{- if .Values.extraEnvVarsSecret }} + - secretRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsSecret "context" $) }} + {{- end }} + {{- end }} + ports: + - name: http + containerPort: {{ .Values.service.ports.http }} + protocol: TCP + - name: admin + containerPort: {{ .Values.service.ports.admin }} + protocol: TCP + {{- if .Values.websockets.enabled }} + - name: ws + containerPort: {{ .Values.service.ports.ws }} + protocol: TCP + {{- end }} + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - name: empty-dir + mountPath: /tmp + - name: empty-dir + mountPath: /home/aries/.acapy_agent/vdr + - name: config + mountPath: "/home/aries/argfile.yml" + subPath: "argfile.yml" + readOnly: true + - name: config + mountPath: "/tmp/ledgers.yml" + subPath: "ledgers.yml" + readOnly: true + - name: config + mountPath: "/home/aries/plugin-config.yml" + subPath: "plugin-config.yml" + readOnly: true + - name: tails-data + mountPath: "/home/aries/.indy_client/tails" + {{- if .Values.extraVolumeMounts }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraVolumeMounts "context" $) | nindent 12 }} + {{- end }} + volumes: + - name: tails-data + {{- if .Values.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ .Values.persistence.existingClaim | default (printf "%s-tails" (include "common.names.fullname" .)) }} + {{- else }} + emptyDir: {} + {{- end }} + - name: empty-dir + emptyDir: {} + - name: config + configMap: + name: {{ printf "%s-config" (include "common.names.fullname" .) }} + {{- if .Values.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraVolumes "context" $) | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/acapy/templates/extra-list.yaml b/charts/acapy/templates/extra-list.yaml new file mode 100644 index 0000000000..9ac65f9e16 --- /dev/null +++ b/charts/acapy/templates/extra-list.yaml @@ -0,0 +1,4 @@ +{{- range .Values.extraDeploy }} +--- +{{ include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- end }} diff --git a/charts/acapy/templates/hpa.yaml b/charts/acapy/templates/hpa.yaml new file mode 100644 index 0000000000..27ec12affe --- /dev/null +++ b/charts/acapy/templates/hpa.yaml @@ -0,0 +1,52 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: {{ include "common.capabilities.hpa.apiVersion" ( dict "context" $ ) }} +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "common.names.fullname" . }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + app.kubernetes.io/component: agent + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "common.names.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} + {{- if or .Values.autoscaling.behavior.scaleDown.policies .Values.autoscaling.behavior.scaleUp.policies }} + behavior: + {{- if .Values.autoscaling.behavior.scaleDown.policies }} + scaleDown: + stabilizationWindowSeconds: {{ .Values.autoscaling.behavior.scaleDown.stabilizationWindowSeconds }} + selectPolicy: {{ .Values.autoscaling.behavior.scaleDown.selectPolicy }} + policies: + {{- toYaml .Values.autoscaling.behavior.scaleDown.policies | nindent 8 }} + {{- end }} + {{- if .Values.autoscaling.behavior.scaleUp.policies }} + scaleUp: + stabilizationWindowSeconds: {{ .Values.autoscaling.behavior.scaleUp.stabilizationWindowSeconds }} + selectPolicy: {{ .Values.autoscaling.behavior.scaleUp.selectPolicy }} + policies: + {{- toYaml .Values.autoscaling.behavior.scaleUp.policies | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/acapy/templates/ingress-admin.yaml b/charts/acapy/templates/ingress-admin.yaml new file mode 100644 index 0000000000..53dd39a953 --- /dev/null +++ b/charts/acapy/templates/ingress-admin.yaml @@ -0,0 +1,57 @@ +{{- if .Values.ingress.admin.enabled }} +apiVersion: {{ include "common.capabilities.ingress.apiVersion" . }} +kind: Ingress +metadata: + name: {{ include "common.names.fullname" . }}-admin + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.ingress.admin.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.ingress.admin.annotations .Values.commonAnnotations ) "context" . ) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.admin.ingressClassName (eq "true" (include "common.ingress.supportsIngressClassname" .)) }} + ingressClassName: {{ .Values.ingress.admin.ingressClassName | quote }} + {{- end }} + rules: + {{- if .Values.ingress.admin.hostname }} + - host: {{ tpl .Values.ingress.admin.hostname $ | quote }} + http: + paths: + {{- if .Values.ingress.admin.extraPaths }} + {{- toYaml .Values.ingress.admin.extraPaths | nindent 10 }} + {{- end }} + - path: {{ .Values.ingress.admin.path }} + {{- if eq "true" (include "common.ingress.supportsPathType" .) }} + pathType: {{ .Values.ingress.admin.pathType }} + {{- end }} + backend: {{- include "common.ingress.backend" (dict "serviceName" (include "common.names.fullname" .) "servicePort" "http" "context" $) | nindent 14 }} + {{- end }} + {{- range .Values.ingress.admin.extraHosts }} + - host: {{ tpl .name $ | quote }} + http: + paths: + - path: {{ default "/" .path }} + {{- if eq "true" (include "common.ingress.supportsPathType" $) }} + pathType: {{ default "ImplementationSpecific" .pathType }} + {{- end }} + backend: {{- include "common.ingress.backend" (dict "serviceName" (include "common.names.fullname" $) "servicePort" "http" "context" $) | nindent 14 }} + {{- end }} + {{- if .Values.ingress.admin.extraRules }} + {{- include "common.tplvalues.render" (dict "value" .Values.ingress.admin.extraRules "context" $) | nindent 4 }} + {{- end }} + {{- if or (and .Values.ingress.admin.tls (or (include "common.ingress.certManagerRequest" ( dict "annotations" .Values.ingress.admin.annotations )) .Values.ingress.admin.selfSigned)) .Values.ingress.admin.extraTls }} + tls: + {{- if and .Values.ingress.admin.tls (or (include "common.ingress.certManagerRequest" ( dict "annotations" .Values.ingress.admin.annotations )) .Values.ingress.admin.selfSigned) }} + - hosts: + - {{ tpl .Values.ingress.admin.hostname $ | quote }} + {{- if and (or (.Values.ingress.admin.tlsWwwPrefix) (eq (index .Values.ingress.admin.annotations "nginx.ingress.kubernetes.io/from-to-www-redirect") "true" )) (not (contains "www." .Values.ingress.admin.hostname)) }} + - {{ printf "www.%s" (tpl .Values.ingress.admin.hostname $) | quote }} + {{- end }} + secretName: {{ printf "%s-tls" (tpl .Values.ingress.admin.hostname $) }} + {{- end }} + {{- if .Values.ingress.admin.extraTls }} + {{- include "common.tplvalues.render" (dict "value" .Values.ingress.admin.extraTls "context" $) | nindent 4 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/acapy/templates/ingress-agent.yaml b/charts/acapy/templates/ingress-agent.yaml new file mode 100644 index 0000000000..f91b15d4d1 --- /dev/null +++ b/charts/acapy/templates/ingress-agent.yaml @@ -0,0 +1,57 @@ +{{- if .Values.ingress.agent.enabled }} +apiVersion: {{ include "common.capabilities.ingress.apiVersion" . }} +kind: Ingress +metadata: + name: {{ include "common.names.fullname" . }}-agent + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.ingress.agent.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.ingress.agent.annotations .Values.commonAnnotations ) "context" . ) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.agent.ingressClassName (eq "true" (include "common.ingress.supportsIngressClassname" .)) }} + ingressClassName: {{ .Values.ingress.agent.ingressClassName | quote }} + {{- end }} + rules: + {{- if .Values.ingress.agent.hostname }} + - host: {{ tpl .Values.ingress.agent.hostname $ | quote }} + http: + paths: + {{- if .Values.ingress.agent.extraPaths }} + {{- toYaml .Values.ingress.agent.extraPaths | nindent 10 }} + {{- end }} + - path: {{ .Values.ingress.agent.path }} + {{- if eq "true" (include "common.ingress.supportsPathType" .) }} + pathType: {{ .Values.ingress.agent.pathType }} + {{- end }} + backend: {{- include "common.ingress.backend" (dict "serviceName" (include "common.names.fullname" .) "servicePort" "http" "context" $) | nindent 14 }} + {{- end }} + {{- range .Values.ingress.agent.extraHosts }} + - host: {{ tpl .name $ | quote }} + http: + paths: + - path: {{ default "/" .path }} + {{- if eq "true" (include "common.ingress.supportsPathType" $) }} + pathType: {{ default "ImplementationSpecific" .pathType }} + {{- end }} + backend: {{- include "common.ingress.backend" (dict "serviceName" (include "common.names.fullname" $) "servicePort" "http" "context" $) | nindent 14 }} + {{- end }} + {{- if .Values.ingress.agent.extraRules }} + {{- include "common.tplvalues.render" (dict "value" .Values.ingress.agent.extraRules "context" $) | nindent 4 }} + {{- end }} + {{- if or (and .Values.ingress.agent.tls (or (include "common.ingress.certManagerRequest" ( dict "annotations" .Values.ingress.agent.annotations )) .Values.ingress.agent.selfSigned)) .Values.ingress.agent.extraTls }} + tls: + {{- if and .Values.ingress.agent.tls (or (include "common.ingress.certManagerRequest" ( dict "annotations" .Values.ingress.agent.annotations )) .Values.ingress.agent.selfSigned) }} + - hosts: + - {{ tpl .Values.ingress.agent.hostname $ | quote }} + {{- if and (or (.Values.ingress.agent.tlsWwwPrefix) (eq (index .Values.ingress.agent.annotations "nginx.ingress.kubernetes.io/from-to-www-redirect") "true" )) (not (contains "www." .Values.ingress.agent.hostname)) }} + - {{ printf "www.%s" (tpl .Values.ingress.agent.hostname $) | quote }} + {{- end }} + secretName: {{ printf "%s-tls" (tpl .Values.ingress.agent.hostname $) }} + {{- end }} + {{- if .Values.ingress.agent.extraTls }} + {{- include "common.tplvalues.render" (dict "value" .Values.ingress.agent.extraTls "context" $) | nindent 4 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/acapy/templates/networkpolicy.yaml b/charts/acapy/templates/networkpolicy.yaml new file mode 100644 index 0000000000..9db3a397c3 --- /dev/null +++ b/charts/acapy/templates/networkpolicy.yaml @@ -0,0 +1,56 @@ +{{- if .Values.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} +metadata: + name: {{ template "common.names.fullname" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + app.kubernetes.io/component: agent + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.podLabels .Values.commonLabels ) "context" . ) }} + podSelector: + matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} + policyTypes: + - Ingress + - Egress + egress: + {{- if .Values.networkPolicy.allowExternalEgress }} + - {} + {{- else }} + - ports: + # Allow dns resolution + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + {{- if .Values.networkPolicy.extraEgress }} + {{- include "common.tplvalues.render" ( dict "value" .Values.networkPolicy.extraEgress "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} + ingress: + - ports: + - port: {{ .Values.containerPorts }} + {{- if not .Values.networkPolicy.allowExternal }} + from: + - podSelector: + matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 14 }} + {{- if .Values.networkPolicy.ingressPodMatchLabels }} + - podSelector: + matchLabels: {{- include "common.tplvalues.render" (dict "value" .Values.networkPolicy.ingressPodMatchLabels "context" $ ) | nindent 14 }} + {{- end }} + {{- if .Values.networkPolicy.ingressNSMatchLabels }} + - namespaceSelector: + matchLabels: {{- include "common.tplvalues.render" (dict "value" .Values.networkPolicy.ingressNSMatchLabels "context" $ ) | nindent 14 }} + {{- if .Values.networkPolicy.ingressNSPodMatchLabels }} + podSelector: + matchLabels: {{- include "common.tplvalues.render" (dict "value" .Values.networkPolicy.ingressNSPodMatchLabels "context" $ ) | nindent 14 }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.networkPolicy.extraIngress }} + {{- include "common.tplvalues.render" ( dict "value" .Values.networkPolicy.extraIngress "context" $ ) | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/acapy/templates/seed-secret.yaml b/charts/acapy/templates/seed-secret.yaml new file mode 100644 index 0000000000..39a65c1a35 --- /dev/null +++ b/charts/acapy/templates/seed-secret.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ printf "%s-seed" (include "common.names.fullname" .) }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + app.kubernetes.io/component: agent + annotations: + helm.sh/resource-policy: keep + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + namespace: {{ .Release.Namespace }} +type: Opaque +data: + seed: {{ include "getOrGeneratePass" (dict "Namespace" .Release.Namespace "Kind" "Secret" "Name" (printf "%s-seed" (include "common.names.fullname" .)) "Key" "seed" "Length" 32) }} diff --git a/charts/acapy/templates/service.yaml b/charts/acapy/templates/service.yaml new file mode 100644 index 0000000000..639ea52a73 --- /dev/null +++ b/charts/acapy/templates/service.yaml @@ -0,0 +1,66 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + app.kubernetes.io/component: agent + {{- if or .Values.service.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.service.annotations .Values.commonAnnotations ) "context" . ) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + {{- if and .Values.service.clusterIP (eq .Values.service.type "ClusterIP") }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} + {{- if or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort") }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy | quote }} + {{- end }} + {{- if and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerSourceRanges)) }} + loadBalancerSourceRanges: {{ .Values.service.loadBalancerSourceRanges }} + {{- end }} + {{- if and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerIP)) }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + {{- if .Values.service.sessionAffinity }} + sessionAffinity: {{ .Values.service.sessionAffinity }} + {{- end }} + {{- if .Values.service.sessionAffinityConfig }} + sessionAffinityConfig: {{- include "common.tplvalues.render" (dict "value" .Values.service.sessionAffinityConfig "context" $) | nindent 4 }} + {{- end }} + ports: + - name: http + port: {{ .Values.service.ports.http }} + protocol: TCP + targetPort: http + {{- if (and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.http))) }} + nodePort: {{ .Values.service.nodePorts.http }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + - name: admin + port: {{ .Values.service.ports.admin }} + protocol: TCP + targetPort: admin + {{- if (and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.admin))) }} + nodePort: {{ .Values.service.nodePorts.admin }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- if .Values.websockets.enabled }} + - name: ws + port: {{ .Values.service.ports.ws }} + protocol: TCP + targetPort: ws + {{- if (and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.ws))) }} + nodePort: {{ .Values.service.nodePorts.ws }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- end }} + {{- if .Values.service.extraPorts }} + {{- include "common.tplvalues.render" (dict "value" .Values.service.extraPorts "context" $) | nindent 4 }} + {{- end }} + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.podLabels .Values.commonLabels ) "context" . ) }} + selector: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 4 }} diff --git a/charts/acapy/templates/serviceaccount.yaml b/charts/acapy/templates/serviceaccount.yaml new file mode 100644 index 0000000000..a404e2bdc1 --- /dev/null +++ b/charts/acapy/templates/serviceaccount.yaml @@ -0,0 +1,10 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "acapy.serviceAccountName" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + app.kubernetes.io/component: agent +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +{{- end }} diff --git a/charts/acapy/templates/tails-pvc.yaml b/charts/acapy/templates/tails-pvc.yaml new file mode 100644 index 0000000000..874a74e92a --- /dev/null +++ b/charts/acapy/templates/tails-pvc.yaml @@ -0,0 +1,23 @@ +{{- if .Values.persistence.enabled }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ printf "%s-tails" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + app.kubernetes.io/component: agent + annotations: + helm.sh/resource-policy: keep + {{- if or .Values.persistence.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.persistence.annotations .Values.commonAnnotations ) "context" . ) }} + {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} + {{- end }} +spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{- include "common.storage.class" (dict "persistence" .Values.persistence "global" .Values.global) | nindent 2 }} +{{- end }} diff --git a/charts/acapy/values.yaml b/charts/acapy/values.yaml new file mode 100644 index 0000000000..f709c14521 --- /dev/null +++ b/charts/acapy/values.yaml @@ -0,0 +1,941 @@ +# Default values for AcaPy. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +## @param global.imageRegistry Global Docker image registry +## @param global.imagePullSecrets Global Docker registry secret names as an array +## @param global.defaultStorageClass Global default StorageClass for Persistent Volume(s) +## +global: + imageRegistry: "" + ## E.g. + ## imagePullSecrets: + ## - myRegistryKeySecretName + ## + imagePullSecrets: [] + defaultStorageClass: "" + ## Security parameters + ## + security: + ## @param global.security.allowInsecureImages Allows skipping image verification + allowInsecureImages: false + ## Compatibility adaptations for Kubernetes platforms + ## + compatibility: + ## Compatibility adaptations for Openshift + ## + openshift: + ## @param global.compatibility.openshift.adaptSecurityContext Adapt the securityContext sections of the deployment to make them compatible with Openshift restricted-v2 SCC: remove runAsUser, runAsGroup and fsGroup and let the platform use their allowed default IDs. Possible values: auto (apply if the detected running cluster is Openshift), force (perform the adaptation always), disabled (do not perform adaptation) + ## + adaptSecurityContext: auto +## @section Common parameters +## +## @param nameOverride String to partially override fullname include (will maintain the release name) +## +nameOverride: "" +## @param fullnameOverride String to fully override fullname template +## +fullnameOverride: "" +## @param namespaceOverride String to fully override common.names.namespace +## +namespaceOverride: "" +## @param kubeVersion Force target Kubernetes version (using Helm capabilities if not set) +## +kubeVersion: "" +## @param commonLabels Labels to add to all deployed objects +## +commonLabels: {} +## @param commonAnnotations Annotations to add to all deployed objects +## +commonAnnotations: {} +## @param replicaCount Number of AcaPy pods +replicaCount: 1 +## @param updateStrategy.type Set up update strategy for AcaPy installation. +## Set to Recreate if you use persistent volume that cannot be mounted by more than one pods to make sure the pods is destroyed first. +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy +## Example: +## updateStrategy: +## type: RollingUpdate +## rollingUpdate: +## maxSurge: 25% +## maxUnavailable: 25% +## +updateStrategy: + type: RollingUpdate +## AcaPy image version +## ref: https://github.com/openwallet-foundation/acapy/pkgs/container/acapy-agent +## @param image.registry [default: REGISTRY_NAME] AcaPy image registry +## @param image.repository [default: REPOSITORY_NAME/AcaPy] AcaPy Image name +## @skip image.tag AcaPy Image tag +## @param image.digest AcaPy image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag +## @param image.pullPolicy AcaPy image pull policy +## @param image.pullSecrets Specify docker-registry secret names as an array +## +image: + registry: ghcr.io + repository: openwallet-foundation/acapy-agent + tag: py3.12-1.2.4 + digest: "" + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + +## @section Configuration files +## +## @descriptionStart +## Configuration file is mounted as is into the container. See the AcaPy documentation for details. +## Note: Secure values of the configuration are passed via equivalent environment variables from secrets. +## @descriptionEnd +## +## @param argfile.yml.admin-insecure-mode Run the admin web server in insecure mode. DO NOT USE FOR PRODUCTION DEPLOYMENTS. The admin server will be publicly available to anyone who has access to the interface. An auto-generated admin API Key is supplied via `ACAPY-ADMIN-API-KEY`. +## @param argfile.yml.auto-accept-invites Automatically accept invites without firing a webhook event or waiting for an admin request. Default: false. +## @param argfile.yml.auto-accept-requests Automatically accept connection requests without firing a webhook event or waiting for an admin request. Default: false. +## @param argfile.yml.auto-create-revocation-transactions For Authors, specify whether to automatically create transactions for a cred def's revocation registry. (If not specified, the controller must invoke the endpoints required to create the revocation registry and assign to the cred def.) +## @param argfile.yml.auto-promote-author-did For authors, specify whether to automatically promote a DID to the wallet public DID after writing to the ledger.`` +## @param argfile.yml.auto-ping-connection Automatically send a trust ping immediately after a connection response is accepted. Some agents require this before marking a connection as 'active'. Default: false. +## @param argfile.yml.auto-provision If the requested profile does not exist, initialize it with the given parameters. +## @param argfile.yml.auto-request-endorsement For Authors, specify whether to automatically request endorsement for all transactions. (If not specified, the controller must invoke the request endorse operation for each transaction.) +## @param argfile.yml.auto-respond-credential-offer Automatically respond to Indy credential offers with a credential request. Default: false +## @param argfile.yml.auto-respond-credential-proposal Auto-respond to credential proposals with corresponding credential offers. +## @param argfile.yml.auto-respond-credential-request Auto-respond to credential requests with corresponding credentials. +## @param argfile.yml.auto-respond-presentation-proposal Auto-respond to presentation proposals with corresponding presentation requests. +## @param argfile.yml.auto-respond-presentation-request Automatically respond to Indy presentation requests with a constructed presentation if a corresponding credential can be retrieved for every referent in the presentation request. Default: false. +## @param argfile.yml.auto-store-credential Automatically store an issued credential upon receipt. Default: false. +## @param argfile.yml.auto-verify-presentation Automatically verify a presentation when it is received. Default: false. +## @param argfile.yml.auto-write-transactions For Authors, specify whether to automatically write any endorsed transactions. (If not specified, the controller must invoke the write transaction operation for each transaction.) +## @param argfile.yml.emit-new-didcomm-mime-type Send packed agent messages with the DIDComm MIME type as of RFC 0044; i.e., 'application/didcomm-envelope-enc' instead of 'application/ssi-agent-wire'. +## @param argfile.yml.emit-new-didcomm-prefix Emit protocol messages with new DIDComm prefix; i.e., 'https://didcomm.org/' instead of (default) prefix 'did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/'. +## @param argfile.yml.endorser-alias For transaction Authors, specify the alias of the Endorser connection that will be used to endorse transactions. +## @param argfile.yml.endorser-protocol-role Specify the role ('author' or 'endorser') which this agent will participate. Authors will request transaction endorsement from an Endorser. Endorsers will endorse transactions from Authors, and may write their own transactions to the ledger. If no role (or 'none') is specified then the endorsement protocol will not be used and this agent will write transactions to the ledger directly. +## @param argfile.yml.auto-respond-messages Automatically respond to basic messages indicating the message was received. Default: false. +## @param argfile.yml.auto-verify-presentation Automatically verify a presentation when it is received. Default: false. +## @param argfile.yml.genesis-transactions-list Load YAML configuration for connecting to multiple HyperLedger Indy ledgers. +## @param argfile.yml.log-level Specifies a custom logging level as one of: ('debug', 'info', 'warning', 'error', 'critical') +## @param argfile.yml.monitor-ping Send a webhook when a ping is sent or received. +## @param argfile.yml.multitenant-admin Specify whether to enable the multitenant admin api. +## @param argfile.yml.multitenant Enable multitenant mode. +## @param argfile.yml.notify-revocation Specifies that aca-py will notify credential recipients when revoking a credential it issued. +## @param argfile.yml.preserve-exchange-records Keep credential exchange records after exchange has completed. +## @param argfile.yml.requests-through-public-did Must be set to true when using "implicit" invitations. +## @param argfile.yml.public-invites Send invitations out using the public DID for the agent, and receive connection requests solicited by invitations which use the public DID. Default: false. +## @param argfile.yml.read-only-ledger Sets ledger to read-only to prevent updates. Default: false. +## @param argfile.yml.wallet-local-did If this parameter is set, provisions the wallet with a local DID from the '--seed' parameter, instead of a public DID to use with a Hyperledger Indy ledger. Default: false. +## @param argfile.yml.wallet-name Specifies the wallet name to be used by the agent. This is useful if your deployment has multiple wallets. +## @param argfile.yml.wallet-storage-type Specifies the type of Indy wallet backend to use. Supported internal storage types are 'basic' (memory), 'default' (sqlite), and 'postgres_storage'. The default, if not specified, is 'default'. +## @param argfile.yml.wallet-type Specifies the type of Indy wallet provider to use. Supported internal storage types are 'basic' (memory) and 'indy'. The default (if not specified) is 'basic'. +## @param argfile.yml.webhook-url Send webhooks containing internal state changes to the specified URL. Optional API key to be passed in the request body can be appended using a hash separator [#]. This is useful for a controller to monitor agent events and respond to those events using the admin API. If not specified, webhooks are not published by the agent. +## +argfile.yml: + admin-insecure-mode: false + auto-accept-invites: true + auto-accept-requests: true + auto-create-revocation-transactions: false + auto-ping-connection: true + auto-promote-author-did: true + auto-provision: true + auto-request-endorsement: false + auto-respond-credential-offer: true + auto-respond-credential-proposal: false + auto-respond-credential-request: false + auto-respond-messages: true + auto-respond-presentation-proposal: true + auto-respond-presentation-request: false + auto-store-credential: true + auto-verify-presentation: false + auto-write-transactions: false + emit-new-didcomm-mime-type: true + emit-new-didcomm-prefix: true + endorser-alias: endorser + endorser-protocol-role: author + genesis-transactions-list: /tmp/ledgers.yml + log-level: info + monitor-ping: false + multitenant-admin: false + multitenant: false + notify-revocation: false + preserve-exchange-records: true + requests-through-public-did: false + public-invites: false + read-only-ledger: true + # tails-server-base-url: https://tails-test.vonx.io + # tails-server-upload-url: https://tails-test.vonx.io + wallet-local-did: true + wallet-name: askar-wallet + wallet-storage-type: postgres_storage + wallet-type: askar + webhook-url: '{{ include "acapy.host" . }}' + +## @param ledgers.yml [object] +ledgers.yml: {} + +## Specify configuration values for each plugin. +## Configuration values are plugin specific, and are rendered as is into the plugin-config.yml file. +## +## @param plugin-config.yml [object] Plugin configuration file +## +plugin-config.yml: {} + +## @param websockets.enabled Enable or disable the websocket transport for the agent. +## +websockets: + enabled: false + +## @section Wallet Storage configuration +## @descriptionStart +## Specifies the storage configuration to use for the wallet. +## This is required if you are for using 'postgres_storage' wallet 'storage type. +## For example, '{"url":"localhost:5432", "wallet_scheme":"MultiWalletSingleTable"}'. +## This configuration maps to the indy sdk postgres plugin (PostgresConfig). +## @descriptionEnd +## +## @param walletStorageConfig.json Raw json, overrides all other values including postgres subchart values. e.g.: '{"url":"localhost:5432", "max_connections":"10", "wallet_scheme":"DatabasePerWallet"}' +## @param walletStorageConfig.url Database url. Overrides all other values including postgres subchart values. +## @param walletStorageConfig.max_connections Client max connections, defaults to 10. +## @param walletStorageConfig.wallet_scheme Wallet scheme. +## +walletStorageConfig: + json: "" + url: "" + max_connections: 10 + wallet_scheme: DatabasePerWallet + +## @section Wallet Storage Credentials +## @descriptionStart +## Specifies the storage credentials to use for the wallet. +## This is required if you are for using 'postgres_storage' wallet 'storage type. +## For example, '{"account":"postgres","password":"mysecretpassword","admin_account":"postgres","admin_password":"mysecretpassword"}'. +## This configuration maps to the indy sdk postgres plugin (PostgresCredential). +## NOTE: admin_user must have the CREATEDB role or else initialization will fail. +## @descriptionEnd +## +## @param walletStorageCredentials.json Raw json with database credentials. Overrides all other values including postgres subchart values. e.g.: '{"account":"postgres","password":"mysecretpassword","admin_account":"postgres","admin_password":"mysecretpassword"}' +## @param walletStorageCredentials.account Database account name. +## @param walletStorageCredentials.admin_account Database account with CREATEDB role used to create additional databases per wallet. +## @param walletStorageCredentials.admin_password Database password for admin account. +## @param walletStorageCredentials.existingSecret Name of an existing secret containing 'database-user', 'database-password', 'admin-password' keys. +## @param walletStorageCredentials.secretKeys.adminPasswordKey Key in existing secret containing admin password. +## @param walletStorageCredentials.secretKeys.userPasswordKey Key in existing secret containing password . +## +walletStorageCredentials: + json: "" + account: acapy + admin_account: postgres + admin_password: "" + existingSecret: "" + secretKeys: + adminPasswordKey: postgres-password + userPasswordKey: password + +## @section Persistence +## Enable persistence using Persistent Volume Claims +## ref: https://kubernetes.io/docs/concepts/storage/persistent-volumes/ +## +persistence: + ## @param persistence.enabled Enable persistence using PVC + ## + enabled: true + ## @param persistence.existingClaim Name of an existing PVC to use + ## + existingClaim: "" + ## @param persistence.storageClass PVC Storage Class for Tails volume + ## If defined, storageClassName: + ## If set to "-", storageClassName: "", which disables dynamic provisioning + ## If undefined (the default) or set to null, no storageClassName spec is + ## set, choosing the default provisioner. (gp2 on AWS, standard on + ## GKE, AWS & OpenStack) + ## + storageClass: "" + ## @param persistence.accessModes PVC Access Mode for Tails volume + ## Requires persistence.enabled: true + ## If defined, PVC must be created manually before volume will be bound + ## + accessModes: + - ReadWriteMany + ## @param persistence.size PVC Storage Request for Tails volume + ## + size: 1Gi + ## @param persistence.annotations Persistent Volume Claim annotations + ## + annotations: {} + +## @section Service and Ports +## AcaPy service parameters +## +service: + ## @param service.type AcaPy service type + ## + type: ClusterIP + ## @param service.ports.http AcaPy service HTTP port + ## @param service.ports.admin AcaPy service admin port + ## @param service.ports.ws AcaPy service websockets port + ## + ports: + http: 8021 + admin: 8022 + ws: 8023 + + ## Node ports to expose + ## @param service.nodePorts.http Node port for HTTP + ## @param service.nodePorts.admin Node port for admin + ## @param service.nodePorts.ws Node port for websockets + ## NOTE: choose port between <30000-32767> + ## + nodePorts: + http: "" + admin: "" + ws: "" + ## @param service.sessionAffinity Control where client requests go, to the same pod or round-robin + ## Values: ClientIP or None + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/ + ## + sessionAffinity: None + ## @param service.sessionAffinityConfig Additional settings for the sessionAffinity + ## sessionAffinityConfig: + ## clientIP: + ## timeoutSeconds: 300 + ## + sessionAffinityConfig: {} + ## @param service.clusterIP AcaPy service Cluster IP + ## e.g.: + ## clusterIP: None + ## + clusterIP: "" + ## @param service.loadBalancerIP AcaPy service Load Balancer IP + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-loadbalancer + ## + loadBalancerIP: "" + ## @param service.loadBalancerSourceRanges AcaPy service Load Balancer sources + ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## e.g: + ## loadBalancerSourceRanges: + ## - 10.10.10.0/24 + ## + loadBalancerSourceRanges: [] + ## @param service.externalTrafficPolicy AcaPy service external traffic policy + ## ref https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + ## + externalTrafficPolicy: Cluster + ## @param service.annotations Additional custom annotations for AcaPy service + ## + annotations: {} + ## @param service.extraPorts Extra port to expose on AcaPy service + ## + extraPorts: [] + +## @section Network Policy +## Network Policies +## Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ +## +networkPolicy: + ## @param networkPolicy.enabled Specifies whether a NetworkPolicy should be created + ## + enabled: true + ## @param networkPolicy.allowExternal Don't require server label for connections + ## The Policy model to apply. When set to false, only pods with the correct + ## server label will have network access to the ports server is listening + ## on. When true, server will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + ## @param networkPolicy.allowExternalEgress Allow the pod to access any range of port and all destinations. + ## + allowExternalEgress: true + ## @param networkPolicy.addExternalClientAccess Allow access from pods with client label set to "true". Ignored if `networkPolicy.allowExternal` is true. + ## + addExternalClientAccess: true + ## @param networkPolicy.extraIngress [array] Add extra ingress rules to the NetworkPolicy + ## e.g: + ## extraIngress: + ## - ports: + ## - port: 1234 + ## from: + ## - podSelector: + ## - matchLabels: + ## - role: frontend + ## - podSelector: + ## - matchExpressions: + ## - key: role + ## operator: In + ## values: + ## - frontend + extraIngress: [] + ## @param networkPolicy.extraEgress [array] Add extra ingress rules to the NetworkPolicy + ## e.g: + ## extraEgress: + ## - ports: + ## - port: 1234 + ## to: + ## - podSelector: + ## - matchLabels: + ## - role: frontend + ## - podSelector: + ## - matchExpressions: + ## - key: role + ## operator: In + ## values: + ## - frontend + ## + extraEgress: [] + ## @param networkPolicy.ingressPodMatchLabels [object] Labels to match to allow traffic from other pods. Ignored if `networkPolicy.allowExternal` is true. + ## e.g: + ## ingressPodMatchLabels: + ## my-client: "true" + # + ingressPodMatchLabels: {} + ## @param networkPolicy.ingressNSMatchLabels [object] Labels to match to allow traffic from other namespaces. Ignored if `networkPolicy.allowExternal` is true. + ## @param networkPolicy.ingressNSPodMatchLabels [object] Pod labels to match to allow traffic from other namespaces. Ignored if `networkPolicy.allowExternal` is true. + ## + ingressNSMatchLabels: {} + ingressNSPodMatchLabels: {} + +## @section Ingress and Endpoint configuration +## Configure the ingress resource that allows you to access the +## AcaPy installation. Set up the URL +## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/ +## +## @param agentUrl must be set if ingress is not enabled +agentUrl: "" +## @param adminUrl must be set if ingress is not enabled +adminUrl: "" +## +ingress: + ## @param ingress.agent.enabled Set to true to enable ingress record generation + ## + agent: + enabled: false + ## @param ingress.agent.pathType Ingress Path type + ## + pathType: ImplementationSpecific + ## @param ingress.agent.apiVersion Override API Version (automatically detected if not set) + ## + apiVersion: "" + ## @param ingress.agent.hostname When the ingress is enabled, a host pointing to this will be created + ## + hostname: acapy.local + ## @param ingress.agent.path Default path for the ingress resource + ## The Path to AcaPy. You may need to set this to '/*' in order to use this with ALB ingress controllers. + ## + path: / + ## @param ingress.agent.annotations Additional annotations for the Ingress resource. To enable certificate autogeneration, place here your cert-manager annotations. + ## For a full list of possible ingress annotations, please see + ## ref: https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md + ## Use this parameter to set the required annotations for cert-manager, see + ## ref: https://cert-manager.io/docs/usage/ingress/#supported-annotations + ## + ## e.g: + ## annotations: + ## kubernetes.io/ingress.class: nginx + ## cert-manager.io/cluster-issuer: cluster-issuer-name + ## + annotations: {} + ## @param ingress.agent.tls Enable TLS configuration for the hostname defined at ingress.hostname parameter + ## TLS certificates will be retrieved from a TLS secret with name: {{- printf "%s-tls" .Values.ingress.hostname }} + ## You can use the ingress.agent.secrets parameter to create this TLS secret or relay on cert-manager to create it + ## + tls: false + ## @param ingress.agent.extraHosts The list of additional hostnames to be covered with this ingress record. + ## Most likely the hostname above will be enough, but in the event more hosts are needed, this is an array + ## extraHosts: + ## - name: acapy.local + ## path: / + ## + extraHosts: [] + ## @param ingress.agent.extraPaths Any additional arbitrary paths that may need to be added to the ingress under the main host. + ## For example: The ALB ingress controller requires a special rule for handling SSL redirection. + ## extraPaths: + ## - path: /* + ## backend: + ## serviceName: ssl-redirect + ## servicePort: use-annotation + ## + extraPaths: [] + ## @param ingress.agent.extraTls The tls configuration for additional hostnames to be covered with this ingress record. + ## see: https://kubernetes.io/docs/concepts/services-networking/ingress/#tls + ## extraTls: + ## - hosts: + ## - acapy.local + ## secretName: acapy.local-tls + ## + extraTls: [] + ## @param ingress.agent.secrets If you're providing your own certificates, please use this to add the certificates as secrets + ## key and certificate should start with -----BEGIN CERTIFICATE----- or + ## -----BEGIN RSA PRIVATE KEY----- + ## + ## name should line up with a tlsSecret set further up + ## If you're using cert-manager, this is unneeded, as it will create the secret for you if it is not set + ## + ## @param ingress.agent.secrets It is also possible to create and manage the certificates outside of this helm chart + ## Please see README.md for more information + ## e.g: + ## - name: acapy.local-tls + ## key: + ## certificate: + ## + secrets: [] + ## @param ingress.agent.selfSigned Create a TLS secret for this ingress record using self-signed certificates generated by Helm + ## + selfSigned: false + ## @param ingress.agent.ingressClassName IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+) + ingressClassName: "" + ## @param ingress.agent.extraRules Additional rules to be covered with this ingress record + ## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-rules + ## e.g: + ## extraRules: + ## - host: example.local + ## http: + ## path: / + ## backend: + ## service: + ## name: example-svc + ## port: + ## name: http + ## + extraRules: [] + ## @param ingress.admin.enabled Set to true to enable ingress record generation + ## + admin: + enabled: false + ## @param ingress.admin.pathType Ingress Path type + ## + pathType: ImplementationSpecific + ## @param ingress.admin.apiVersion Override API Version (automatically detected if not set) + ## + apiVersion: "" + ## @param ingress.admin.hostname When the ingress is enabled, a host pointing to this will be created + ## + hostname: admin.acapy.local + ## @param ingress.admin.path Default path for the ingress resource + ## The Path to AcaPy. You may need to set this to '/*' in order to use this with ALB ingress controllers. + ## + path: / + ## @param ingress.admin.annotations Additional annotations for the Ingress resource. To enable certificate autogeneration, place here your cert-manager annotations. + ## For a full list of possible ingress annotations, please see + ## ref: https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md + ## Use this parameter to set the required annotations for cert-manager, see + ## ref: https://cert-manager.io/docs/usage/ingress/#supported-annotations + ## + ## e.g: + ## annotations: + ## kubernetes.io/ingress.class: nginx + ## cert-manager.io/cluster-issuer: cluster-issuer-name + ## + annotations: {} + ## @param ingress.admin.tls Enable TLS configuration for the hostname defined at ingress.hostname parameter + ## TLS certificates will be retrieved from a TLS secret with name: {{- printf "%s-tls" .Values.ingress.hostname }} + ## You can use the ingress.admin.secrets parameter to create this TLS secret or relay on cert-manager to create it + ## + tls: false + ## @param ingress.admin.extraHosts The list of additional hostnames to be covered with this ingress record. + ## Most likely the hostname above will be enough, but in the event more hosts are needed, this is an array + ## extraHosts: + ## - name: acapy.local + ## path: / + ## + extraHosts: [] + ## @param ingress.admin.extraPaths Any additional arbitrary paths that may need to be added to the ingress under the main host. + ## For example: The ALB ingress controller requires a special rule for handling SSL redirection. + ## extraPaths: + ## - path: /* + ## backend: + ## serviceName: ssl-redirect + ## servicePort: use-annotation + ## + extraPaths: [] + ## @param ingress.admin.extraTls The tls configuration for additional hostnames to be covered with this ingress record. + ## see: https://kubernetes.io/docs/concepts/services-networking/ingress/#tls + ## extraTls: + ## - hosts: + ## - acapy.local + ## secretName: acapy.local-tls + ## + extraTls: [] + ## @param ingress.admin.secrets If you're providing your own certificates, please use this to add the certificates as secrets + ## key and certificate should start with -----BEGIN CERTIFICATE----- or + ## -----BEGIN RSA PRIVATE KEY----- + ## + ## name should line up with a tlsSecret set further up + ## If you're using cert-manager, this is unneeded, as it will create the secret for you if it is not set + ## + ## @param ingress.admin.secrets It is also possible to create and manage the certificates outside of this helm chart + ## Please see README.md for more information + ## e.g: + ## - name: acapy.local-tls + ## key: + ## certificate: + ## + secrets: [] + ## @param ingress.admin.selfSigned Create a TLS secret for this ingress record using self-signed certificates generated by Helm + ## + selfSigned: false + ## @param ingress.admin.ingressClassName IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+) + ingressClassName: "" + ## @param ingress.admin.extraRules Additional rules to be covered with this ingress record + ## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-rules + ## e.g: + ## extraRules: + ## - host: example.local + ## http: + ## path: / + ## backend: + ## service: + ## name: example-svc + ## port: + ## name: http + ## + extraRules: [] + +## @section Deployment parameters +## AcaPy container's resource requests and limits +## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ +## We usually recommend not to specify default resources and to leave this as a conscious +## choice for the user. This also increases chances charts run on environments with little +## resources, such as Minikube. If you do want to specify resources, uncomment the following +## lines, adjust them as necessary, and remove the curly braces after 'resources:'. +## @param resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if resources is set (resources is recommended for production). +## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 +## +resourcesPreset: "none" +## @param resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) +## Example: +## resources: +## requests: +## cpu: 2 +## memory: 512Mi +## limits: +## cpu: 3 +## memory: 1024Mi +## +resources: {} + +## AcaPy pods' liveness probe. Evaluated as a template. +## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes +## @param livenessProbe.enabled Enable livenessProbe +## @param livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe +## @param livenessProbe.periodSeconds Period seconds for livenessProbe +## @param livenessProbe.timeoutSeconds Timeout seconds for livenessProbe +## @param livenessProbe.failureThreshold Failure threshold for livenessProbe +## @param livenessProbe.successThreshold Success threshold for livenessProbe +## @param livenessProbe.httpGet.path Request path for livenessProbe +## @param livenessProbe.httpGet.port Port for livenessProbe +## +livenessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 20 + timeoutSeconds: 10 + failureThreshold: 6 + successThreshold: 1 + httpGet: + path: /status/live + port: admin +## AcaPy pods' readiness probe. Evaluated as a template. +## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes +## @param readinessProbe.enabled Enable readinessProbe +## @param readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe +## @param readinessProbe.periodSeconds Period seconds for readinessProbe +## @param readinessProbe.timeoutSeconds Timeout seconds for readinessProbe +## @param readinessProbe.failureThreshold Failure threshold for readinessProbe +## @param readinessProbe.successThreshold Success threshold for readinessProbe +## @param readinessProbe.httpGet.path Request path for readinessProbe +## @param readinessProbe.httpGet.port Port for readinessProbe +## +readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + httpGet: + path: /status/ready + port: admin +## @param initContainers Add additional init containers for the hidden node pod(s) +## Example: +## initContainers: +## - name: your-image-name +## image: your-image +## imagePullPolicy: Always +## ports: +## - name: portname +## containerPort: 1234 +## +initContainers: [] +## +## @param extraArgs Array containing extra command line arguments to configure aca-py +## For example: +## extraArgs: +## - --my-arg=my-value +## - --my-flag +extraArgs: [] +## +## @param extraEnvVarsCM Name of existing ConfigMap containing extra env vars +## +extraEnvVarsCM: "" +## @param extraEnvVarsSecret Name of existing Secret containing extra env vars +## +extraEnvVarsSecret: "" +## @param extraEnvVars Array containing extra env vars to configure AcaPy +## For example: +## extraEnvVars: +## - name: GF_DEFAULT_INSTANCE_NAME +## value: my-instance +## +extraEnvVars: [] +## Node affinity preset +## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity +## @param nodeAffinityPreset.type Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` +## @param nodeAffinityPreset.key Node label key to match Ignored if `affinity` is set. +## @param nodeAffinityPreset.values Node label values to match. Ignored if `affinity` is set. +## +nodeAffinityPreset: + type: "" + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] +## @param affinity Affinity for pod assignment +## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity +## Note: podAffinityPreset, podAntiAffinityPreset, and nodeAffinityPreset will be ignored when it's set +## +affinity: {} +## @param podAffinityPreset Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` +## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity +## +podAffinityPreset: "" +## @param podAntiAffinityPreset Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` +## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity +## +podAntiAffinityPreset: soft +## Node affinity preset +## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity +## +## @param nodeSelector Node labels for pod assignment +## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ +## +nodeSelector: {} +## @param tolerations Tolerations for pod assignment +## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ +## +tolerations: [] +## @param topologySpreadConstraints Topology spread constraints rely on node labels to identify the topology domain(s) that each Node is in +## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ +## +## topologySpreadConstraints: +## - maxSkew: 1 +## topologyKey: failure-domain.beta.kubernetes.io/zone +## whenUnsatisfiable: DoNotSchedule +## +topologySpreadConstraints: [] +## @param podLabels Pod labels +## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ +## +podLabels: {} +## @param podAnnotations Pod annotations +## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ +## +podAnnotations: {} + +## @param extraVolumes Array of extra volumes to be added to the deployment (evaluated as template). Requires setting `extraVolumeMounts` +## +extraVolumes: [] +# - name: foo +# secret: +# secretName: mysecret +# optional: false + +## @param extraVolumeMounts Array of extra volume mounts to be added to the container (evaluated as template). Normally used with `extraVolumes`. +## +extraVolumeMounts: [] +# - name: foo +# mountPath: "/etc/foo" +# readOnly: true + +## @param extraDeploy Array of extra objects to deploy with the release +## +extraDeploy: [] +## @section PostgreSQL Parameters +## + +## @section Autoscaling +## Autoscaling configuration +## ref: https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/ +## @param autoscaling.enabled Enable Horizontal POD autoscaling for AcaPy +## @param autoscaling.minReplicas Minimum number of AcaPy replicas +## @param autoscaling.maxReplicas Maximum number of AcaPy replicas +## @param autoscaling.targetCPUUtilizationPercentage Target CPU utilization percentage +## @param autoscaling.targetMemoryUtilizationPercentage Target Memory utilization percentage +## +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 10 + targetCPUUtilizationPercentage: 80 + targetMemoryUtilizationPercentage: 80 + ## HPA Scaling Behavior + ## ref: https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#configurable-scaling-behavior + ## + behavior: + ## HPA behavior when scaling up + ## @param autoscaling.behavior.scaleUp.stabilizationWindowSeconds The number of seconds for which past recommendations should be considered while scaling up + ## @param autoscaling.behavior.scaleUp.selectPolicy The priority of policies that the autoscaler will apply when scaling up + ## @param autoscaling.behavior.scaleUp.policies [array] HPA scaling policies when scaling up + ## e.g: + ## Policy to scale 20% of the pod in 60s + ## - type: Percent + ## value: 20 + ## periodSeconds: 60 + ## + scaleUp: + stabilizationWindowSeconds: 60 + selectPolicy: Max + policies: [] + ## HPA behavior when scaling down + ## @param autoscaling.behavior.scaleDown.stabilizationWindowSeconds The number of seconds for which past recommendations should be considered while scaling down + ## @param autoscaling.behavior.scaleDown.selectPolicy The priority of policies that the autoscaler will apply when scaling down + ## @param autoscaling.behavior.scaleDown.policies [array] HPA scaling policies when scaling down + ## e.g: + ## Policy to scale one pod in 300s + ## - type: Pods + ## value: 1 + ## periodSeconds: 300 + ## + scaleDown: + stabilizationWindowSeconds: 120 + selectPolicy: Max + policies: + - type: Pods + value: 1 + periodSeconds: 300 + +## @section RBAC and Security settings +## Pods Service Account +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + ## @param serviceAccount.create Enable creation of ServiceAccount for acapy pod + ## + create: true + ## @param serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the `common.names.fullname` template + name: "" + ## @param serviceAccount.annotations Annotations for service account. Evaluated as a template. + ## Only used if `create` is `true`. + ## + annotations: {} + ## @param serviceAccount.automountServiceAccountToken Auto-mount token for the Service Account + ## + automountServiceAccountToken: false +## @param automountServiceAccountToken Auto-mount token in pod +## +automountServiceAccountToken: false +## @param podSecurityContext.enabled Enable securityContext on for AcaPy deployment +## @param podSecurityContext.fsGroupChangePolicy Set filesystem group change policy +## @param podSecurityContext.sysctls Set kernel settings using the sysctl interface +## @param podSecurityContext.supplementalGroups Set filesystem extra groups +## @param podSecurityContext.fsGroup Group to configure permissions for volumes +## +podSecurityContext: + enabled: true + fsGroupChangePolicy: Always + sysctls: [] + supplementalGroups: [] + fsGroup: 1001 +## Configure Container Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod +## @param containerSecurityContext.enabled Enabled containers' Security Context +## @param containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in container +## @param containerSecurityContext.runAsUser Set containers' Security Context runAsUser +## @param containerSecurityContext.runAsGroup Set containers' Security Context runAsGroup +## @param containerSecurityContext.runAsNonRoot Set container's Security Context runAsNonRoot +## @param containerSecurityContext.privileged Set container's Security Context privileged +## @param containerSecurityContext.readOnlyRootFilesystem Set container's Security Context readOnlyRootFilesystem +## @param containerSecurityContext.allowPrivilegeEscalation Set container's Security Context allowPrivilegeEscalation +## @param containerSecurityContext.capabilities.drop List of capabilities to be dropped +## @param containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile +## +containerSecurityContext: + enabled: true + seLinuxOptions: {} + runAsUser: 1001 + runAsGroup: 1001 + runAsNonRoot: true + privileged: false + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: ["ALL"] + seccompProfile: + type: "RuntimeDefault" + +## @section PostgreSQL Parameters +## PostgreSQL chart configuration +## ref: https://github.com/bitnami/charts/blob/main/bitnami/postgresql/values.yaml +## @param postgresql.enabled Switch to enable or disable the PostgreSQL helm chart +## @param postgresql.auth.username Name for a custom user to create +## @param postgresql.auth.database Name for a custom database to create +## @param postgresql.auth.enablePostgresUser Assign a password to the "postgres" admin user. Otherwise, remote access will be blocked for this user. Not recommended for production deployments. +## @param postgresql.auth.existingSecret Name of existing secret to use for PostgreSQL credentials +## @param postgresql.architecture PostgreSQL architecture (`standalone` or `replication`) +## +postgresql: + enabled: true + auth: + username: acapy + database: "" + enablePostgresUser: true + existingSecret: "" + architecture: standalone + primary: + persistence: + ## @param postgresql.primary.persistence.enabled Enable PostgreSQL Primary data persistence using PVC + ## + enabled: true + ## @param postgresql.primary.persistence.size PVC Storage Request for PostgreSQL volume + ## + size: 1Gi + ## Container Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## @param postgresql.primary.containerSecurityContext.enabled Enable container security context + ## + containerSecurityContext: + enabled: false + ## Pod Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## @param postgresql.primary.podSecurityContext.enabled Enable security context + ## + podSecurityContext: + enabled: false + ## PostgreSQL Primary resource requests and limits + ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + ## @param postgresql.primary.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, small, medium, large, xlarge, 2xlarge). This is ignored if primary.resources is set (primary.resources is recommended for production). + ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 + ## + resourcesPreset: "nano" + ## @param postgresql.primary.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) + ## Example: + ## resources: + ## requests: + ## cpu: 2 + ## memory: 512Mi + ## limits: + ## cpu: 3 + ## memory: 1024Mi + ## + resources: {} + ## @param postgresql.primary.extendedConfiguration Extended PostgreSQL Primary configuration (appended to main or default configuration) + ## ref: https://github.com/bitnami/containers/tree/main/bitnami/postgresql#allow-settings-to-be-loaded-from-files-other-than-the-default-postgresqlconf + ## + extendedConfiguration: | + max_connections = 500 From d7d4815fc96937539a89957e3c8452e339b0094b Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Thu, 27 Mar 2025 21:26:33 +0200 Subject: [PATCH 53/76] :art: Use correct model for sending AnonCreds presentation (#3618) * :bug: Correct AnonCreds presentation schema Signed-off-by: ff137 * :art: Update validation error Signed-off-by: ff137 --------- Signed-off-by: ff137 --- acapy_agent/protocols/present_proof/v2_0/routes.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/acapy_agent/protocols/present_proof/v2_0/routes.py b/acapy_agent/protocols/present_proof/v2_0/routes.py index 1aef1b9bb2..5839f0a4a6 100644 --- a/acapy_agent/protocols/present_proof/v2_0/routes.py +++ b/acapy_agent/protocols/present_proof/v2_0/routes.py @@ -18,6 +18,7 @@ from ....admin.request_context import AdminRequestContext from ....anoncreds.holder import AnonCredsHolder, AnonCredsHolderError from ....anoncreds.models.presentation_request import AnoncredsPresentationRequestSchema +from ....anoncreds.models.proof import AnoncredsPresSpecSchema from ....connections.models.conn_record import ConnRecord from ....indy.holder import IndyHolder, IndyHolderError from ....indy.models.cred_precis import IndyCredPrecisSchema @@ -233,7 +234,8 @@ def validate_fields(self, data, **kwargs): """ if not any(f.api in data for f in V20PresFormat.Format): raise ValidationError( - "V20PresRequestByFormatSchema requires indy, dif, or both" + "V20PresRequestByFormatSchema requires at least one of: " + "anoncreds, indy, dif" ) @@ -310,7 +312,7 @@ class V20PresSpecByFormatRequestSchema(AdminAPIMessageTracingSchema): """Presentation specification schema by format, for send-presentation request.""" anoncreds = fields.Nested( - IndyPresSpecSchema, + AnoncredsPresSpecSchema, required=False, metadata={"description": "Presentation specification for anoncreds"}, ) @@ -1236,7 +1238,7 @@ async def present_proof_send_presentation(request: web.BaseRequest): raise web.HTTPBadRequest( reason=( "No presentation format specification provided, " - "either dif or indy must be included. " + "either dif, anoncreds or indy must be included. " "In case of DIF, if no additional specification " 'needs to be provided then include "dif": {}' ) From cdfe8b4bc947b140470d0a3090980cf711302852 Mon Sep 17 00:00:00 2001 From: David Chaiken Date: Thu, 27 Mar 2025 16:17:03 -0700 Subject: [PATCH 54/76] chore(demo): remove aip 10 code (#3619) Signed-off-by: David Chaiken Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- demo/runners/agent_container.py | 17 +- demo/runners/faber.py | 692 ++++++++++++-------------------- 2 files changed, 268 insertions(+), 441 deletions(-) diff --git a/demo/runners/agent_container.py b/demo/runners/agent_container.py index 83fdfcb1b5..499bb7741f 100644 --- a/demo/runners/agent_container.py +++ b/demo/runners/agent_container.py @@ -1376,7 +1376,7 @@ def arg_parser(ident: str = None, port: int = 8020): type=str, default=20, metavar=(""), - help="API level (10 or 20 (default))", + help="API level (20)", ) parser.add_argument("--timing", action="store_true", help="Enable timing information") parser.add_argument( @@ -1546,11 +1546,10 @@ async def create_agent_with_args(args, ident: str = None, extra_args: list = Non if "aip" in args: aip = int(args.aip) - if aip not in [ - 10, - 20, - ]: - raise Exception("Invalid value for aip, should be 10 or 20") + if aip == 10: # helpful message to flag legacy usage + raise Exception("Invalid value for aip, 10 is no longer supported. Use 20 instead.") + if aip != 20: + raise Exception("Invalid value for aip, should be 20") else: aip = 20 @@ -1582,16 +1581,10 @@ async def create_agent_with_args(args, ident: str = None, extra_args: list = Non ) reuse_connections = "reuse_connections" in args and args.reuse_connections - # if reuse_connections and aip != 20: - # raise Exception("Can only specify `--reuse-connections` with AIP 2.0") multi_use_invitations = "multi_use_invitations" in args and args.multi_use_invitations - if multi_use_invitations and aip != 20: - raise Exception("Can only specify `--multi-use-invitations` with AIP 2.0") public_did_connections = ( "public_did_connections" in args and args.public_did_connections ) - if public_did_connections and aip != 20: - raise Exception("Can only specify `--public-did-connections` with AIP 2.0") anoncreds_legacy_revocation = None if "anoncreds_legacy_revocation" in args and args.anoncreds_legacy_revocation: diff --git a/demo/runners/faber.py b/demo/runners/faber.py index 57ea76c62e..765090a6dc 100644 --- a/demo/runners/faber.py +++ b/demo/runners/faber.py @@ -79,13 +79,12 @@ async def detect_connection(self): def connection_ready(self): return self._connection_ready.done() and self._connection_ready.result() - def generate_credential_offer(self, aip, cred_type, cred_def_id, exchange_tracing): + def generate_credential_offer(self, cred_type, cred_def_id, exchange_tracing): age = 24 d = datetime.date.today() birth_date = datetime.date(d.year - age, d.month, d.day) birth_date_format = "%Y%m%d" - if aip == 10: - # define attributes to send for credential + if cred_type == CRED_FORMAT_ANONCREDS or cred_type == CRED_FORMAT_INDY: self.cred_attrs[cred_def_id] = { "name": "Alice Smith", "date": "2018-05-28", @@ -101,120 +100,90 @@ def generate_credential_offer(self, aip, cred_type, cred_def_id, exchange_tracin for (n, v) in self.cred_attrs[cred_def_id].items() ], } + if cred_type == CRED_FORMAT_INDY: + _filter = {"indy": {"cred_def_id": cred_def_id}} + else: + _filter = {"anoncreds": {"cred_def_id": cred_def_id}} offer_request = { "connection_id": self.connection_id, - "cred_def_id": cred_def_id, "comment": f"Offer on cred def id {cred_def_id}", "auto_remove": False, "credential_preview": cred_preview, + "filter": _filter, "trace": exchange_tracing, } return offer_request - elif aip == 20: - if cred_type == CRED_FORMAT_ANONCREDS or cred_type == CRED_FORMAT_INDY: - self.cred_attrs[cred_def_id] = { - "name": "Alice Smith", - "date": "2018-05-28", - "degree": "Maths", - "birthdate_dateint": birth_date.strftime(birth_date_format), - "timestamp": str(int(time.time())), - } - - cred_preview = { - "@type": CRED_PREVIEW_TYPE, - "attributes": [ - {"name": n, "value": v} - for (n, v) in self.cred_attrs[cred_def_id].items() - ], - } - if cred_type == CRED_FORMAT_INDY: - _filter = {"indy": {"cred_def_id": cred_def_id}} - else: - _filter = {"anoncreds": {"cred_def_id": cred_def_id}} - offer_request = { - "connection_id": self.connection_id, - "comment": f"Offer on cred def id {cred_def_id}", - "auto_remove": False, - "credential_preview": cred_preview, - "filter": _filter, - "trace": exchange_tracing, - } - return offer_request - - elif cred_type == CRED_FORMAT_VC_DI: - self.cred_attrs[cred_def_id] = { - "name": "Alice Smith", - "date": "2018-05-28", - "degree": "Maths", - "birthdate_dateint": birth_date.strftime(birth_date_format), - "timestamp": str(int(time.time())), - } + elif cred_type == CRED_FORMAT_VC_DI: + self.cred_attrs[cred_def_id] = { + "name": "Alice Smith", + "date": "2018-05-28", + "degree": "Maths", + "birthdate_dateint": birth_date.strftime(birth_date_format), + "timestamp": str(int(time.time())), + } - cred_preview = { - "@type": CRED_PREVIEW_TYPE, - "attributes": [ - {"name": n, "value": v} - for (n, v) in self.cred_attrs[cred_def_id].items() - ], - } - offer_request = { - "connection_id": self.connection_id, - "comment": f"Offer on cred def id {cred_def_id}", - "auto_remove": False, - "credential_preview": cred_preview, - "filter": {"vc_di": {"cred_def_id": cred_def_id}}, - "trace": exchange_tracing, - } - return offer_request + cred_preview = { + "@type": CRED_PREVIEW_TYPE, + "attributes": [ + {"name": n, "value": v} + for (n, v) in self.cred_attrs[cred_def_id].items() + ], + } + offer_request = { + "connection_id": self.connection_id, + "comment": f"Offer on cred def id {cred_def_id}", + "auto_remove": False, + "credential_preview": cred_preview, + "filter": {"vc_di": {"cred_def_id": cred_def_id}}, + "trace": exchange_tracing, + } + return offer_request - elif cred_type == CRED_FORMAT_JSON_LD: - offer_request = { - "connection_id": self.connection_id, - "filter": { - "ld_proof": { - "credential": { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://w3id.org/citizenship/v1", - "https://w3id.org/security/bbs/v1", - ], - "type": [ - "VerifiableCredential", - "PermanentResident", - ], - "id": "https://credential.example.com/residents/1234567890", - "issuer": self.did, - "issuanceDate": "2020-01-01T12:00:00Z", - "credentialSubject": { - "type": ["PermanentResident"], - "givenName": "ALICE", - "familyName": "SMITH", - "gender": "Female", - "birthCountry": "Bahamas", - "birthDate": "1958-07-17", - }, + elif cred_type == CRED_FORMAT_JSON_LD: + offer_request = { + "connection_id": self.connection_id, + "filter": { + "ld_proof": { + "credential": { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/citizenship/v1", + "https://w3id.org/security/bbs/v1", + ], + "type": [ + "VerifiableCredential", + "PermanentResident", + ], + "id": "https://credential.example.com/residents/1234567890", + "issuer": self.did, + "issuanceDate": "2020-01-01T12:00:00Z", + "credentialSubject": { + "type": ["PermanentResident"], + "givenName": "ALICE", + "familyName": "SMITH", + "gender": "Female", + "birthCountry": "Bahamas", + "birthDate": "1958-07-17", }, - "options": {"proofType": SIG_TYPE_BLS}, - } - }, - } - return offer_request - - else: - raise Exception(f"Error invalid credential type: {self.cred_type}") + }, + "options": {"proofType": SIG_TYPE_BLS}, + } + }, + } + return offer_request else: - raise Exception(f"Error invalid AIP level: {self.aip}") + raise Exception(f"Error invalid credential type: {self.cred_type}") def generate_proof_request_web_request( - self, aip, cred_type, revocation, exchange_tracing, connectionless=False + self, cred_type, revocation, exchange_tracing, connectionless=False ): age = 18 d = datetime.date.today() birth_date = datetime.date(d.year - age, d.month, d.day) birth_date_format = "%Y%m%d" - if aip == 10: + if cred_type == CRED_FORMAT_ANONCREDS or cred_type == CRED_FORMAT_INDY: req_attrs = [ { "name": "name", @@ -261,236 +230,170 @@ def generate_proof_request_web_request( f"0_{req_attr['name']}_uuid": req_attr for req_attr in req_attrs }, "requested_predicates": { - f"0_{req_pred['name']}_GE_uuid": req_pred for req_pred in req_preds + f"0_{req_pred['name']}_GE_uuid": req_pred + for req_pred in req_preds }, } if revocation: proof_request["non_revoked"] = {"to": int(time.time())} + if cred_type == CRED_FORMAT_ANONCREDS: + presentation_request = {"anoncreds": proof_request} + else: + presentation_request = {"indy": proof_request} proof_request_web_request = { - "proof_request": proof_request, + "presentation_request": presentation_request, "trace": exchange_tracing, } if not connectionless: proof_request_web_request["connection_id"] = self.connection_id + return proof_request_web_request - elif aip == 20: - if cred_type == CRED_FORMAT_ANONCREDS or cred_type == CRED_FORMAT_INDY: - req_attrs = [ - { - "name": "name", - "restrictions": [{"schema_name": "degree schema"}], - }, - { - "name": "date", - "restrictions": [{"schema_name": "degree schema"}], - }, - ] - if revocation: - req_attrs.append( - { - "name": "degree", - "restrictions": [{"schema_name": "degree schema"}], - "non_revoked": {"to": int(time.time() - 1)}, + elif cred_type == CRED_FORMAT_VC_DI: + proof_request_web_request = { + "comment": "Test proof request for VC-DI format", + "presentation_request": { + "dif": { + "options": { + "challenge": "3fa85f64-5717-4562-b3fc-2c963f66afa7", + "domain": "4jt78h47fh47", }, - ) - else: - req_attrs.append( - { - "name": "degree", - "restrictions": [{"schema_name": "degree schema"}], - } - ) - if SELF_ATTESTED: - # test self-attested claims - req_attrs.append( - {"name": "self_attested_thing"}, - ) - req_preds = [ - # test zero-knowledge proofs - { - "name": "birthdate_dateint", - "p_type": "<=", - "p_value": int(birth_date.strftime(birth_date_format)), - "restrictions": [{"schema_name": "degree schema"}], - } - ] - proof_request = { - "name": "Proof of Education", - "version": "1.0", - "requested_attributes": { - f"0_{req_attr['name']}_uuid": req_attr for req_attr in req_attrs - }, - "requested_predicates": { - f"0_{req_pred['name']}_GE_uuid": req_pred - for req_pred in req_preds - }, - } - - if revocation: - proof_request["non_revoked"] = {"to": int(time.time())} - - if cred_type == CRED_FORMAT_ANONCREDS: - presentation_request = {"anoncreds": proof_request} - else: - presentation_request = {"indy": proof_request} - proof_request_web_request = { - "presentation_request": presentation_request, - "trace": exchange_tracing, - } - if not connectionless: - proof_request_web_request["connection_id"] = self.connection_id - - return proof_request_web_request - - elif cred_type == CRED_FORMAT_VC_DI: - proof_request_web_request = { - "comment": "Test proof request for VC-DI format", - "presentation_request": { - "dif": { - "options": { - "challenge": "3fa85f64-5717-4562-b3fc-2c963f66afa7", - "domain": "4jt78h47fh47", - }, - "presentation_definition": { - "id": "5591656f-5b5d-40f8-ab5c-9041c8e3a6a0", - "name": "Age Verification", - "purpose": "We need to verify your age before entering a bar", - "input_descriptors": [ - { - "id": "age-verification", - "name": "A specific type of VC + Issuer", - "purpose": "We want a VC of this type generated by this issuer", - "schema": [ + "presentation_definition": { + "id": "5591656f-5b5d-40f8-ab5c-9041c8e3a6a0", + "name": "Age Verification", + "purpose": "We need to verify your age before entering a bar", + "input_descriptors": [ + { + "id": "age-verification", + "name": "A specific type of VC + Issuer", + "purpose": "We want a VC of this type generated by this issuer", + "schema": [ + { + "uri": "https://www.w3.org/2018/credentials#VerifiableCredential" + } + ], + "constraints": { + "statuses": { + "active": {"directive": "disallowed"} + }, + "limit_disclosure": "required", + "fields": [ { - "uri": "https://www.w3.org/2018/credentials#VerifiableCredential" - } - ], - "constraints": { - "statuses": { - "active": {"directive": "disallowed"} - }, - "limit_disclosure": "required", - "fields": [ - { - "path": ["$.issuer"], - "filter": { - "type": "string", - "const": self.did, - }, + "path": ["$.issuer"], + "filter": { + "type": "string", + "const": self.did, }, - {"path": ["$.credentialSubject.name"]}, - {"path": ["$.credentialSubject.degree"]}, - { - "path": [ - "$.credentialSubject.birthdate_dateint" - ], - "predicate": "preferred", - "filter": { - "type": "number", - "maximum": int( - birth_date.strftime( - birth_date_format - ) - ), - }, + }, + {"path": ["$.credentialSubject.name"]}, + {"path": ["$.credentialSubject.degree"]}, + { + "path": [ + "$.credentialSubject.birthdate_dateint" + ], + "predicate": "preferred", + "filter": { + "type": "number", + "maximum": int( + birth_date.strftime( + birth_date_format + ) + ), }, - ], - }, - } - ], - "format": { - "di_vc": { - "proof_type": ["DataIntegrityProof"], - "cryptosuite": [ - "anoncreds-2023", - "eddsa-rdfc-2022", + }, ], - } - }, + }, + } + ], + "format": { + "di_vc": { + "proof_type": ["DataIntegrityProof"], + "cryptosuite": [ + "anoncreds-2023", + "eddsa-rdfc-2022", + ], + } }, }, }, - } + }, + } - if revocation: - proof_request_web_request["presentation_request"]["dif"][ - "presentation_definition" - ]["input_descriptors"][0]["constraints"]["statuses"]["active"][ - "directive" - ] = "required" - if not connectionless: - proof_request_web_request["connection_id"] = self.connection_id - return proof_request_web_request + if revocation: + proof_request_web_request["presentation_request"]["dif"][ + "presentation_definition" + ]["input_descriptors"][0]["constraints"]["statuses"]["active"][ + "directive" + ] = "required" + if not connectionless: + proof_request_web_request["connection_id"] = self.connection_id + return proof_request_web_request - elif cred_type == CRED_FORMAT_JSON_LD: - proof_request_web_request = { - "comment": "test proof request for json-ld", - "presentation_request": { - "dif": { - "options": { - "challenge": "3fa85f64-5717-4562-b3fc-2c963f66afa7", - "domain": "4jt78h47fh47", - }, - "presentation_definition": { - "id": "32f54163-7166-48f1-93d8-ff217bdb0654", - "format": {"ldp_vp": {"proof_type": [SIG_TYPE_BLS]}}, - "input_descriptors": [ - { - "id": "citizenship_input_1", - "name": "EU Driver's License", - "schema": [ + elif cred_type == CRED_FORMAT_JSON_LD: + proof_request_web_request = { + "comment": "test proof request for json-ld", + "presentation_request": { + "dif": { + "options": { + "challenge": "3fa85f64-5717-4562-b3fc-2c963f66afa7", + "domain": "4jt78h47fh47", + }, + "presentation_definition": { + "id": "32f54163-7166-48f1-93d8-ff217bdb0654", + "format": {"ldp_vp": {"proof_type": [SIG_TYPE_BLS]}}, + "input_descriptors": [ + { + "id": "citizenship_input_1", + "name": "EU Driver's License", + "schema": [ + { + "uri": "https://www.w3.org/2018/credentials#VerifiableCredential" + }, + { + "uri": "https://w3id.org/citizenship#PermanentResident" + }, + ], + "constraints": { + "limit_disclosure": "required", + "is_holder": [ + { + "directive": "required", + "field_id": [ + "1f44d55f-f161-4938-a659-f8026467f126" + ], + } + ], + "fields": [ { - "uri": "https://www.w3.org/2018/credentials#VerifiableCredential" + "id": "1f44d55f-f161-4938-a659-f8026467f126", + "path": [ + "$.credentialSubject.familyName" + ], + "purpose": "The claim must be from one of the specified person", + "filter": {"const": "SMITH"}, }, { - "uri": "https://w3id.org/citizenship#PermanentResident" + "path": [ + "$.credentialSubject.givenName" + ], + "purpose": "The claim must be from one of the specified person", }, ], - "constraints": { - "limit_disclosure": "required", - "is_holder": [ - { - "directive": "required", - "field_id": [ - "1f44d55f-f161-4938-a659-f8026467f126" - ], - } - ], - "fields": [ - { - "id": "1f44d55f-f161-4938-a659-f8026467f126", - "path": [ - "$.credentialSubject.familyName" - ], - "purpose": "The claim must be from one of the specified person", - "filter": {"const": "SMITH"}, - }, - { - "path": [ - "$.credentialSubject.givenName" - ], - "purpose": "The claim must be from one of the specified person", - }, - ], - }, - } - ], - }, - } - }, - } - if not connectionless: - proof_request_web_request["connection_id"] = self.connection_id - return proof_request_web_request - - else: - raise Exception(f"Error invalid credential type: {self.cred_type}") + }, + } + ], + }, + } + }, + } + if not connectionless: + proof_request_web_request["connection_id"] = self.connection_id + return proof_request_web_request else: - raise Exception(f"Error invalid AIP level: {self.aip}") + raise Exception(f"Error invalid credential type: {self.cred_type}") async def main(args): @@ -697,170 +600,101 @@ async def main(args): elif option == "1": log_status("#13 Issue credential offer to X") - if faber_agent.aip == 10: + if faber_agent.cred_type in [ + CRED_FORMAT_ANONCREDS, + CRED_FORMAT_INDY, + CRED_FORMAT_VC_DI, + ]: offer_request = faber_agent.agent.generate_credential_offer( - faber_agent.aip, None, faber_agent.cred_def_id, exchange_tracing + faber_agent.cred_type, + faber_agent.cred_def_id, + exchange_tracing, ) - await faber_agent.agent.admin_POST( - "/issue-credential/send-offer", offer_request - ) - - elif faber_agent.aip == 20: - if faber_agent.cred_type in [ - CRED_FORMAT_ANONCREDS, - CRED_FORMAT_INDY, - CRED_FORMAT_VC_DI, - ]: - offer_request = faber_agent.agent.generate_credential_offer( - faber_agent.aip, - faber_agent.cred_type, - faber_agent.cred_def_id, - exchange_tracing, - ) - - elif faber_agent.cred_type == CRED_FORMAT_JSON_LD: - offer_request = faber_agent.agent.generate_credential_offer( - faber_agent.aip, - faber_agent.cred_type, - None, - exchange_tracing, - ) - else: - raise Exception( - f"Error invalid credential type: {faber_agent.cred_type}" - ) - - await faber_agent.agent.admin_POST( - "/issue-credential-2.0/send-offer", offer_request + elif faber_agent.cred_type == CRED_FORMAT_JSON_LD: + offer_request = faber_agent.agent.generate_credential_offer( + faber_agent.cred_type, + None, + exchange_tracing, ) else: - raise Exception(f"Error invalid AIP level: {faber_agent.aip}") + raise Exception( + f"Error invalid credential type: {faber_agent.cred_type}" + ) + + await faber_agent.agent.admin_POST( + "/issue-credential-2.0/send-offer", offer_request + ) elif option == "2": log_status("#20 Request proof of degree from alice") - if faber_agent.aip == 10: + if faber_agent.cred_type in [ + CRED_FORMAT_ANONCREDS, + CRED_FORMAT_INDY, + CRED_FORMAT_VC_DI, + CRED_FORMAT_JSON_LD, + ]: proof_request_web_request = ( faber_agent.agent.generate_proof_request_web_request( - faber_agent.aip, faber_agent.cred_type, faber_agent.revocation, exchange_tracing, ) ) - await faber_agent.agent.admin_POST( - "/present-proof/send-request", proof_request_web_request - ) - pass - - elif faber_agent.aip == 20: - if faber_agent.cred_type in [ - CRED_FORMAT_ANONCREDS, - CRED_FORMAT_INDY, - CRED_FORMAT_VC_DI, - CRED_FORMAT_JSON_LD, - ]: - proof_request_web_request = ( - faber_agent.agent.generate_proof_request_web_request( - faber_agent.aip, - faber_agent.cred_type, - faber_agent.revocation, - exchange_tracing, - ) - ) - else: - raise Exception( - "Error invalid credential type:" + faber_agent.cred_type - ) - log_status( - "Send a proof request to X: " - + json.dumps(proof_request_web_request) - ) - await agent.admin_POST( - "/present-proof-2.0/send-request", proof_request_web_request - ) - else: - raise Exception(f"Error invalid AIP level: {faber_agent.aip}") + raise Exception( + "Error invalid credential type:" + faber_agent.cred_type + ) + log_status( + "Send a proof request to X: " + + json.dumps(proof_request_web_request) + ) + await agent.admin_POST( + "/present-proof-2.0/send-request", proof_request_web_request + ) elif option == "2a": log_status("#20 Request * Connectionless * proof of degree from alice") - if faber_agent.aip == 10: + if faber_agent.cred_type in [ + CRED_FORMAT_ANONCREDS, + CRED_FORMAT_INDY, + CRED_FORMAT_VC_DI, + CRED_FORMAT_JSON_LD, + ]: proof_request_web_request = ( faber_agent.agent.generate_proof_request_web_request( - faber_agent.aip, faber_agent.cred_type, faber_agent.revocation, exchange_tracing, connectionless=True, ) ) - proof_request = await faber_agent.agent.admin_POST( - "/present-proof/create-request", proof_request_web_request - ) - pres_req_id = proof_request["presentation_exchange_id"] - url = ( - os.getenv("WEBHOOK_TARGET") - or ( - "http://" - + os.getenv("DOCKERHOST").replace( - "{PORT}", str(faber_agent.agent.admin_port + 1) - ) - + "/webhooks" - ) - ) + f"/pres_req/{pres_req_id}/" - log_msg(f"Proof request url: {url}") - qr = QRCode(border=1) - qr.add_data(url) - log_msg( - "Scan the following QR code to accept the proof request from a mobile agent." + else: + raise Exception( + "Error invalid credential type:" + faber_agent.cred_type ) - qr.print_ascii(invert=True) - elif faber_agent.aip == 20: - if faber_agent.cred_type in [ - CRED_FORMAT_ANONCREDS, - CRED_FORMAT_INDY, - CRED_FORMAT_VC_DI, - CRED_FORMAT_JSON_LD, - ]: - proof_request_web_request = ( - faber_agent.agent.generate_proof_request_web_request( - faber_agent.aip, - faber_agent.cred_type, - faber_agent.revocation, - exchange_tracing, - connectionless=True, - ) - ) - else: - raise Exception( - "Error invalid credential type:" + faber_agent.cred_type - ) - - proof_request = await faber_agent.agent.admin_POST( - "/present-proof-2.0/create-request", proof_request_web_request - ) - pres_req_id = proof_request["pres_ex_id"] - url = ( - "http://" - + os.getenv("DOCKERHOST").replace( - "{PORT}", str(faber_agent.agent.admin_port + 1) - ) - + "/webhooks/pres_req/" - + pres_req_id - + "/" - ) - log_msg(f"Proof request url: {url}") - qr = QRCode(border=1) - qr.add_data(url) - log_msg( - "Scan the following QR code to accept the proof request from a mobile agent." + proof_request = await faber_agent.agent.admin_POST( + "/present-proof-2.0/create-request", proof_request_web_request + ) + pres_req_id = proof_request["pres_ex_id"] + url = ( + "http://" + + os.getenv("DOCKERHOST").replace( + "{PORT}", str(faber_agent.agent.admin_port + 1) ) - qr.print_ascii(invert=True) - else: - raise Exception(f"Error invalid AIP level: {faber_agent.aip}") + + "/webhooks/pres_req/" + + pres_req_id + + "/" + ) + log_msg(f"Proof request url: {url}") + qr = QRCode(border=1) + qr.add_data(url) + log_msg( + "Scan the following QR code to accept the proof request from a mobile agent." + ) + qr.print_ascii(invert=True) elif option == "3": msg = await prompt("Enter message: ") From 117cc56ea8786e53b664b4296ec21d13423cb6fd Mon Sep 17 00:00:00 2001 From: Yuki I <42908250+MonolithicMonk@users.noreply.github.com> Date: Fri, 28 Mar 2025 11:05:57 -0500 Subject: [PATCH 55/76] fix: align ledger config schema with API response (#3615) * fix: align ledger config schema with API response - Replace ledger_config_list with production/non_production_ledgers - Add missing fields to LedgerConfigInstanceSchema - Update OpenAPI documentation Resolves #123 Signed-off-by: Yuki I * test: add coverage for ledger config schemas - Validate schema structure and required fields - Test UUID generation in LedgerConfigInstanceSchema - Verify production/non-production ledger grouping Signed-off-by: Yuki I * fix: final schema and test adjustments Signed-off-by: Yuki I --------- Signed-off-by: Yuki I Co-authored-by: Yuki I --- .../multiple_ledger/ledger_config_schema.py | 88 +++++++++++--- acapy_agent/ledger/tests/test_routes.py | 114 +++++++++++++++++- conftest.py | 2 +- demo/runners/acme.py | 1 - demo/runners/alice.py | 2 +- demo/runners/performance.py | 4 +- demo/runners/support/agent.py | 2 +- scenarios/examples/json_ld/example.py | 6 +- scenarios/examples/multitenancy/example.py | 13 +- 9 files changed, 200 insertions(+), 32 deletions(-) diff --git a/acapy_agent/ledger/multiple_ledger/ledger_config_schema.py b/acapy_agent/ledger/multiple_ledger/ledger_config_schema.py index d2a300a7c8..21db5015cf 100644 --- a/acapy_agent/ledger/multiple_ledger/ledger_config_schema.py +++ b/acapy_agent/ledger/multiple_ledger/ledger_config_schema.py @@ -21,17 +21,25 @@ def __init__( self, *, id: Optional[str] = None, - is_production: str = True, - genesis_transactions: Optional[str] = None, - genesis_file: Optional[str] = None, - genesis_url: Optional[str] = None, + is_production: bool = True, + is_write: bool = False, + keepalive: int = 5, + read_only: bool = False, + socks_proxy: Optional[str] = None, + pool_name: Optional[str] = None, + endorser_alias: Optional[str] = None, + endorser_did: Optional[str] = None, ): """Initialize LedgerConfigInstance.""" - self.id = id + self.id = id or str(uuid4()) self.is_production = is_production - self.genesis_transactions = genesis_transactions - self.genesis_file = genesis_file - self.genesis_url = genesis_url + self.is_write = is_write + self.keepalive = keepalive + self.read_only = read_only + self.socks_proxy = socks_proxy + self.pool_name = pool_name or self.id + self.endorser_alias = endorser_alias + self.endorser_did = endorser_did class LedgerConfigInstanceSchema(BaseModelSchema): @@ -43,13 +51,46 @@ class Meta: model_class = LedgerConfigInstance unknown = EXCLUDE - id = fields.Str(required=False, metadata={"description": "ledger_id"}) - is_production = fields.Bool(required=False, metadata={"description": "is_production"}) - genesis_transactions = fields.Str( - required=False, metadata={"description": "genesis_transactions"} + id = fields.Str( + required=True, + metadata={ + "description": "Ledger identifier. Auto-generated UUID4 if not provided", + "example": "f47ac10b-58cc-4372-a567-0e02b2c3d479", + }, + ) + is_production = fields.Bool( + required=True, metadata={"description": "Production-grade ledger (true/false)"} + ) + is_write = fields.Bool( + required=False, + metadata={"description": "Write capability enabled (default: False)"}, + ) + keepalive = fields.Int( + required=False, + metadata={ + "description": "Keep-alive timeout in seconds for idle connections", + "default": 5, + }, + ) + read_only = fields.Bool( + required=False, metadata={"description": "Read-only access (default: False)"} + ) + socks_proxy = fields.Str( + required=False, metadata={"description": "SOCKS proxy URL (optional)"} + ) + pool_name = fields.Str( + required=False, + metadata={ + "description": "Ledger pool name (defaults to ledger ID if not specified)", + "example": "bcovrin-test-pool", + }, + ) + endorser_alias = fields.Str( + required=False, metadata={"description": "Endorser service alias (optional)"} + ) + endorser_did = fields.Str( + required=False, metadata={"description": "Endorser DID (optional)"} ) - genesis_file = fields.Str(required=False, metadata={"description": "genesis_file"}) - genesis_url = fields.Str(required=False, metadata={"description": "genesis_url"}) @pre_load def validate_id(self, data, **kwargs): @@ -58,12 +99,27 @@ def validate_id(self, data, **kwargs): data["id"] = str(uuid4()) return data + @pre_load + def set_defaults(self, data, **kwargs): + """Set default values for optional fields.""" + data.setdefault("is_write", False) + data.setdefault("keepalive", 5) + data.setdefault("read_only", False) + return data + class LedgerConfigListSchema(OpenAPISchema): """Schema for Ledger Config List.""" - ledger_config_list = fields.List( - fields.Nested(LedgerConfigInstanceSchema(), required=True), required=True + production_ledgers = fields.List( # Changed from ledger_config_list + fields.Nested(LedgerConfigInstanceSchema(), required=True), + required=True, + metadata={"description": "Production ledgers (may be empty)"}, + ) + non_production_ledgers = fields.List( # Added new field + fields.Nested(LedgerConfigInstanceSchema(), required=True), + required=True, + metadata={"description": "Non-production ledgers (may be empty)"}, ) diff --git a/acapy_agent/ledger/tests/test_routes.py b/acapy_agent/ledger/tests/test_routes.py index 03532fd3a3..d673ad857d 100644 --- a/acapy_agent/ledger/tests/test_routes.py +++ b/acapy_agent/ledger/tests/test_routes.py @@ -1,6 +1,10 @@ import json +import pytest +import uuid +from marshmallow import ValidationError from typing import Optional from unittest import IsolatedAsyncioTestCase +from uuid_utils import uuid4 from ...connections.models.conn_record import ConnRecord from ...ledger.base import BaseLedger @@ -9,7 +13,11 @@ from ...ledger.multiple_ledger.ledger_requests_executor import ( IndyLedgerRequestsExecutor, ) -from ...ledger.multiple_ledger.ledger_config_schema import ConfigurableWriteLedgersSchema +from ...ledger.multiple_ledger.ledger_config_schema import ( + ConfigurableWriteLedgersSchema, + LedgerConfigInstanceSchema, + LedgerConfigListSchema, +) from ...multitenant.base import BaseMultitenantManager from ...multitenant.manager import MultitenantManager @@ -869,6 +877,110 @@ async def test_get_ledger_config_x(self): with self.assertRaises(test_module.web.HTTPForbidden): await test_module.get_ledger_config(self.request) + async def test_get_ledger_config_structure(self): + """Test the structure of the ledger config response.""" + mock_manager = mock.MagicMock(BaseMultipleLedgerManager, autospec=True) + mock_manager.get_prod_ledgers = mock.CoroutineMock(return_value={"test_1": None}) + mock_manager.get_nonprod_ledgers = mock.CoroutineMock( + return_value={"test_2": None} + ) + self.profile.context.injector.bind_instance( + BaseMultipleLedgerManager, mock_manager + ) + + self.context.settings["ledger.ledger_config_list"] = [ + { + "id": "test_1", + "is_production": True, + "is_write": True, + "keepalive": 5, + "read_only": False, + "pool_name": "test_pool", + "socks_proxy": None, + }, + { + "id": "test_2", + "is_production": False, + "is_write": False, + "keepalive": 10, + "read_only": True, + "pool_name": "non_prod_pool", + "socks_proxy": None, + }, + ] + + with mock.patch.object( + test_module.web, "json_response", mock.Mock() + ) as json_response: + await test_module.get_ledger_config(self.request) + + response_data = json_response.call_args[0][0] + assert "production_ledgers" in response_data + assert "non_production_ledgers" in response_data + + prod_ledger = response_data["production_ledgers"][0] + assert prod_ledger == { + "id": "test_1", + "is_production": True, + "is_write": True, + "keepalive": 5, + "read_only": False, + "pool_name": "test_pool", + "socks_proxy": None, + } + + non_prod_ledger = response_data["non_production_ledgers"][0] + assert non_prod_ledger == { + "id": "test_2", + "is_production": False, + "is_write": False, + "keepalive": 10, + "read_only": True, + "pool_name": "non_prod_pool", + "socks_proxy": None, + } + + async def test_ledger_config_schema_validation(self): + """Test schema validation for required fields.""" + schema = LedgerConfigInstanceSchema() + + minimal_data = { + "is_production": True, + "is_write": False, + "keepalive": 5, + "read_only": False, + } + loaded = schema.load(minimal_data) + assert loaded.pool_name == loaded.id + assert loaded.is_write is False + + with pytest.raises(ValidationError) as exc: + schema.load({"is_production": "not_bool"}) + assert "is_production" in exc.value.messages + + async def test_ledger_config_id_generation(self): + """Test automatic ID generation when missing.""" + schema = LedgerConfigInstanceSchema() + + data = { + "is_production": True, + "is_write": False, # Add required fields + "keepalive": 5, + "read_only": False, + } + loaded = schema.load(data) + assert uuid.UUID(loaded.id, version=4) + + explicit_id = str(uuid4()) + loaded = schema.load({"id": explicit_id, "is_production": True}) + assert loaded.id == explicit_id + + async def test_empty_ledger_lists(self): + schema = LedgerConfigListSchema() + empty_data = {"production_ledgers": [], "non_production_ledgers": []} + loaded = schema.load(empty_data) + assert loaded == empty_data + # Multiple Ledgers Configured async def test_get_write_ledgers_multiple(self): # Mock the multiple ledger manager diff --git a/conftest.py b/conftest.py index 16262bba93..51c760b702 100644 --- a/conftest.py +++ b/conftest.py @@ -147,7 +147,7 @@ def stub_ursa_bbs_signatures() -> Stub: def pytest_sessionstart(session): global STUBS, POSTGRES_URL, ENABLE_PTVSD args = sys.argv - + # copied from __main__.py:init_debug ENABLE_PTVSD = os.getenv("ENABLE_PTVSD", "").lower() ENABLE_PTVSD = ENABLE_PTVSD and ENABLE_PTVSD not in ("false", "0") diff --git a/demo/runners/acme.py b/demo/runners/acme.py index cb17342675..61208ba8be 100644 --- a/demo/runners/acme.py +++ b/demo/runners/acme.py @@ -14,7 +14,6 @@ check_requires, log_msg, log_status, - log_timer, prompt, prompt_loop, ) diff --git a/demo/runners/alice.py b/demo/runners/alice.py index 999803eb1b..093531d143 100644 --- a/demo/runners/alice.py +++ b/demo/runners/alice.py @@ -158,7 +158,7 @@ async def main(args): log_status("#9 Input faber.py invitation details") await input_invitation(alice_agent) - options = " (3) Send Message\n" " (4) Input New Invitation\n" + options = " (3) Send Message\n (4) Input New Invitation\n" if alice_agent.endorser_role and alice_agent.endorser_role == "author": options += " (D) Set Endorser's DID\n" if alice_agent.multitenant: diff --git a/demo/runners/performance.py b/demo/runners/performance.py index 9776f0ae06..b8468d38d5 100644 --- a/demo/runners/performance.py +++ b/demo/runners/performance.py @@ -457,7 +457,7 @@ def done_send(fut: asyncio.Task): def test_cred(index: int) -> dict: return { "name": "Alice Smith", - "date": f"{2020+index}-05-28", + "date": f"{2020 + index}-05-28", "degree": "Maths", "age": "24", } @@ -579,7 +579,7 @@ async def check_received_pings(agent, issue_count, pb): avg = recv_timer.duration / issue_count item_short = "ping" if action == "ping" else "cred" item_long = "ping exchange" if action == "ping" else "credential" - faber.log(f"Average time per {item_long}: {avg:.2f}s ({1/avg:.2f}/s)") + faber.log(f"Average time per {item_long}: {avg:.2f}s ({1 / avg:.2f}/s)") if alice.postgres: await alice.collect_postgres_stats(f"{issue_count} {item_short}s") diff --git a/demo/runners/support/agent.py b/demo/runners/support/agent.py index fd77ae38b3..383eab90f2 100644 --- a/demo/runners/support/agent.py +++ b/demo/runners/support/agent.py @@ -1783,7 +1783,7 @@ async def connect_wallet_to_endorser(agent, endorser_agent): # setup endorser meta-data on our connection log_msg("Setup author agent meta-data ...") await agent.admin_POST( - f"/transactions/{agent.endorser_connection_id }/set-endorser-role", + f"/transactions/{agent.endorser_connection_id}/set-endorser-role", params={"transaction_my_job": "TRANSACTION_AUTHOR"}, ) endorser_did = endorser_agent.endorser_public_did diff --git a/scenarios/examples/json_ld/example.py b/scenarios/examples/json_ld/example.py index 7fa8bf3705..1629335fc0 100644 --- a/scenarios/examples/json_ld/example.py +++ b/scenarios/examples/json_ld/example.py @@ -278,7 +278,7 @@ async def main(): { "path": ["$.issuer"], "purpose": "The claim must be from one of the specified issuers", # noqa: E501 - "filter": {"const": p256_alice_did} + "filter": {"const": p256_alice_did}, }, { "path": ["$.credentialSubject.givenName"], @@ -289,9 +289,7 @@ async def main(): } ], "id": str(uuid4()), - "format": { - "ldp_vp": {"proof_type": ["EcdsaSecp256r1Signature2019"]} - }, + "format": {"ldp_vp": {"proof_type": ["EcdsaSecp256r1Signature2019"]}}, }, domain="test-degree", ) diff --git a/scenarios/examples/multitenancy/example.py b/scenarios/examples/multitenancy/example.py index 097fc69352..2d8b2529c9 100644 --- a/scenarios/examples/multitenancy/example.py +++ b/scenarios/examples/multitenancy/example.py @@ -42,11 +42,14 @@ async def main(): response=CreateWalletResponse, ) - async with Controller( - base_url=AGENCY, wallet_id=alice.wallet_id, subwallet_token=alice.token - ) as alice, Controller( - base_url=AGENCY, wallet_id=bob.wallet_id, subwallet_token=bob.token - ) as bob: + async with ( + Controller( + base_url=AGENCY, wallet_id=alice.wallet_id, subwallet_token=alice.token + ) as alice, + Controller( + base_url=AGENCY, wallet_id=bob.wallet_id, subwallet_token=bob.token + ) as bob, + ): # Issuance prep config = (await alice.get("/status/config"))["config"] genesis_url = config.get("ledger.genesis_url") From ea1343951268a2a6d303348701e2c8001512714a Mon Sep 17 00:00:00 2001 From: David Chaiken Date: Fri, 28 Mar 2025 14:29:59 -0700 Subject: [PATCH 56/76] fix(demo): set PUBLIC_TAILS_URL only if ngrok is running Signed-off-by: David Chaiken --- demo/ngrok-wait.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/demo/ngrok-wait.sh b/demo/ngrok-wait.sh index cc9100daba..c47d19ab33 100755 --- a/demo/ngrok-wait.sh +++ b/demo/ngrok-wait.sh @@ -21,8 +21,13 @@ if ! [ -z "$TAILS_NGROK_NAME" ]; then else echo " not found" fi - export PUBLIC_TAILS_URL=$NGROK_ENDPOINT - echo "Fetched ngrok tails server endpoint [$PUBLIC_TAILS_URL]" + if [ -z "$NGROK_ENDPOINT" ] || [ "$NGROK_ENDPOINT" = "null" ]; then + # setting PUBLIC_TAILS_URL to null confuses the agent because "null" is a truthy value in Python + echo "PUBLIC_TAILS_URL not set and ngrok not available" + else + export PUBLIC_TAILS_URL=$NGROK_ENDPOINT + echo "Fetched ngrok tails server endpoint [$PUBLIC_TAILS_URL]" + fi fi export AGENT_NAME=$1 From f08c31f8eff2f8b6e0e1c321b6bf35921d8fcd03 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Mar 2025 15:31:50 -0700 Subject: [PATCH 57/76] chore(deps-dev): Bump pytest-asyncio from 0.25.3 to 0.26.0 (#3621) Bumps [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) from 0.25.3 to 0.26.0. - [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases) - [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v0.25.3...v0.26.0) --- updated-dependencies: - dependency-name: pytest-asyncio dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index b6c0311e6d..e4a3ba1a1d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2380,14 +2380,14 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments [[package]] name = "pytest-asyncio" -version = "0.25.3" +version = "0.26.0" description = "Pytest support for asyncio" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pytest_asyncio-0.25.3-py3-none-any.whl", hash = "sha256:9e89518e0f9bd08928f97a3482fdc4e244df17529460bc038291ccaf8f85c7c3"}, - {file = "pytest_asyncio-0.25.3.tar.gz", hash = "sha256:fc1da2cf9f125ada7e710b4ddad05518d4cee187ae9412e9ac9271003497f07a"}, + {file = "pytest_asyncio-0.26.0-py3-none-any.whl", hash = "sha256:7b51ed894f4fbea1340262bdae5135797ebbe21d8638978e35d31c6d19f72fb0"}, + {file = "pytest_asyncio-0.26.0.tar.gz", hash = "sha256:c4df2a697648241ff39e7f0e4a73050b03f123f760673956cf0d72a4990e312f"}, ] [package.dependencies] @@ -2973,4 +2973,4 @@ didcommv2 = ["didcomm-messaging"] [metadata] lock-version = "2.1" python-versions = "^3.12" -content-hash = "d1bf934d30d520d31137e9b3d2c4ef69206c9ff2a74a2c1268c15cccb48d7783" +content-hash = "1a902795ad6eb2188cd8e1d5a804524edbb895f3d7abe5fd39fe4a42d7331d7b" diff --git a/pyproject.toml b/pyproject.toml index 8c9766d1a2..24c1f3d935 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,7 +80,7 @@ pydevd-pycharm = "^251.17181.23" # testing pytest = "^8.3.4" -pytest-asyncio = "^0.25.3" +pytest-asyncio = ">=0.25.3,<0.27.0" pytest-cov = "^6.0.0" pytest-ruff = "^0.4.1" pytest-xdist = "^3.6.1" From 6ef36b76e8b1176373f233dab20994ed36b6dd0a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Mar 2025 16:01:22 -0700 Subject: [PATCH 58/76] chore(deps): Bump pytest-asyncio in /demo/playground/examples (#3620) Bumps [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) from 0.25.3 to 0.26.0. - [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases) - [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v0.25.3...v0.26.0) --- updated-dependencies: - dependency-name: pytest-asyncio dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stephen Curran --- demo/playground/examples/poetry.lock | 26 ++++++++++++++++++------- demo/playground/examples/pyproject.toml | 2 +- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/demo/playground/examples/poetry.lock b/demo/playground/examples/poetry.lock index 7b4a867c7e..578d1d96fa 100644 --- a/demo/playground/examples/poetry.lock +++ b/demo/playground/examples/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. [[package]] name = "certifi" @@ -6,6 +6,7 @@ version = "2025.1.31" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, @@ -17,6 +18,7 @@ version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, @@ -118,6 +120,8 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main"] +markers = "sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -129,6 +133,7 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -143,6 +148,7 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -154,6 +160,7 @@ version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, @@ -165,6 +172,7 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -180,6 +188,7 @@ version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, @@ -196,13 +205,14 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments [[package]] name = "pytest-asyncio" -version = "0.25.3" +version = "0.26.0" description = "Pytest support for asyncio" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ - {file = "pytest_asyncio-0.25.3-py3-none-any.whl", hash = "sha256:9e89518e0f9bd08928f97a3482fdc4e244df17529460bc038291ccaf8f85c7c3"}, - {file = "pytest_asyncio-0.25.3.tar.gz", hash = "sha256:fc1da2cf9f125ada7e710b4ddad05518d4cee187ae9412e9ac9271003497f07a"}, + {file = "pytest_asyncio-0.26.0-py3-none-any.whl", hash = "sha256:7b51ed894f4fbea1340262bdae5135797ebbe21d8638978e35d31c6d19f72fb0"}, + {file = "pytest_asyncio-0.26.0.tar.gz", hash = "sha256:c4df2a697648241ff39e7f0e4a73050b03f123f760673956cf0d72a4990e312f"}, ] [package.dependencies] @@ -218,6 +228,7 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -239,18 +250,19 @@ version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = "^3.12" -content-hash = "6aa7dd5266368b13c5fbe3336506288281e262f4dac274d990b3809764ced9e0" +content-hash = "945992542d52f0038aa98468e67064e38beb7951c4552e1dd252e1299f462137" diff --git a/demo/playground/examples/pyproject.toml b/demo/playground/examples/pyproject.toml index cd646a934c..b6f63df241 100644 --- a/demo/playground/examples/pyproject.toml +++ b/demo/playground/examples/pyproject.toml @@ -8,7 +8,7 @@ package-mode=false [tool.poetry.dependencies] python = "^3.12" pytest = "^8.3.4" -pytest-asyncio = "^0.25.3" +pytest-asyncio = "^0.26.0" requests = "^2.32.3" [build-system] From 27c59f9cb95e62f25897474d6acbd02b93e59706 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Tue, 1 Apr 2025 09:20:36 +1000 Subject: [PATCH 59/76] fix and regression test Signed-off-by: George Mulhearn --- .../default_verification_key_strategy.py | 2 +- .../test_default_verification_key_strategy.py | 57 ++++++++++++++++++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/acapy_agent/wallet/default_verification_key_strategy.py b/acapy_agent/wallet/default_verification_key_strategy.py index 982ebc12aa..be9eb0de36 100644 --- a/acapy_agent/wallet/default_verification_key_strategy.py +++ b/acapy_agent/wallet/default_verification_key_strategy.py @@ -104,7 +104,7 @@ async def get_verification_method_id_for_did( doc_raw = await resolver.resolve(profile=profile, did=did) doc = DIDDocument.deserialize(doc_raw) - methods_or_refs = getattr(doc, proof_purpose, []) + methods_or_refs = doc_raw.get(proof_purpose, []) # Dereference any refs in the verification relationship methods = [ await resolver.dereference_verification_method(profile, method, document=doc) diff --git a/acapy_agent/wallet/tests/test_default_verification_key_strategy.py b/acapy_agent/wallet/tests/test_default_verification_key_strategy.py index 0a644d7757..48396c8ff7 100644 --- a/acapy_agent/wallet/tests/test_default_verification_key_strategy.py +++ b/acapy_agent/wallet/tests/test_default_verification_key_strategy.py @@ -2,6 +2,7 @@ import pytest from acapy_agent.resolver.did_resolver import DIDResolver +from ...resolver.tests.test_did_resolver import MockResolver from ...did.did_key import DIDKey from ...utils.testing import create_test_profile @@ -12,11 +13,44 @@ TEST_DID_SOV = "did:sov:LjgpST2rjsoxYegQDRm7EL" TEST_DID_KEY = "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL" - class TestDefaultVerificationKeyStrategy(IsolatedAsyncioTestCase): async def asyncSetUp(self) -> None: self.profile = await create_test_profile() resolver = DIDResolver() + resolver.register_resolver( + MockResolver( + ["example"], + resolved= { + "@context": [ + "https://www.w3.org/ns/did/v1", + "https://w3id.org/security/multikey/v1", + ], + "id": "did:example:123", + "verificationMethod": [ + { + "id": "did:example:123#key-1", + "type": "Multikey", + "controller": "did:example:123", + "publicKeyMultibase": "z6MkjYXizfaAXTriV3h2Vc9uxJ9AMQpfG7mE1WKMnn1KJvFE", + }, + { + "id": "did:example:123#key-2", + "type": "Multikey", + "controller": "did:example:123", + "publicKeyMultibase": "z6MkjYXizfaAXTriV3h2Vc9uxJ9AMQpfG7mE1WKMnn1KJvFE", + }, + { + "id": "did:example:123#key-3", + "type": "Ed25519VerificationKey2018", + "controller": "did:example:123", + "publicKeyBase58": "66GgQRKjBvNFNYrKp3C57CbAXqYorEWsKVQRxW3JPhTr", + }, + ], + "authentication": ["did:example:123#key-1"], + "assertionMethod": ["did:example:123#key-2", "did:example:123#key-3"], + } + ) + ) self.profile.context.injector.bind_instance(DIDResolver, resolver) async def test_with_did_sov(self): @@ -32,6 +66,27 @@ async def test_with_did_key(self): await strategy.get_verification_method_id_for_did(TEST_DID_KEY, self.profile) == DIDKey.from_did(TEST_DID_KEY).key_id ) + + async def test_with_did_for_assertion(self): + strategy = DefaultVerificationKeyStrategy() + assert ( + await strategy.get_verification_method_id_for_did( + "did:example:123", + self.profile, + proof_type="Ed25519Signature2020", + proof_purpose="assertionMethod" + ) + == "did:example:123#key-2" + ) + assert ( + await strategy.get_verification_method_id_for_did( + "did:example:123", + self.profile, + proof_type="Ed25519Signature2018", + proof_purpose="assertionMethod" + ) + == "did:example:123#key-3" + ) async def test_unsupported_did_method(self): strategy = DefaultVerificationKeyStrategy() From 7788dee38b3da4feeedf1e89c97f010ac9687ec6 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Tue, 1 Apr 2025 09:32:43 +1000 Subject: [PATCH 60/76] fmt? Signed-off-by: George Mulhearn --- .../wallet/tests/test_default_verification_key_strategy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acapy_agent/wallet/tests/test_default_verification_key_strategy.py b/acapy_agent/wallet/tests/test_default_verification_key_strategy.py index 48396c8ff7..3d80443bb3 100644 --- a/acapy_agent/wallet/tests/test_default_verification_key_strategy.py +++ b/acapy_agent/wallet/tests/test_default_verification_key_strategy.py @@ -66,7 +66,7 @@ async def test_with_did_key(self): await strategy.get_verification_method_id_for_did(TEST_DID_KEY, self.profile) == DIDKey.from_did(TEST_DID_KEY).key_id ) - + async def test_with_did_for_assertion(self): strategy = DefaultVerificationKeyStrategy() assert ( From 1e805cbd6e042a4af3bd1054a830304db683a914 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Tue, 1 Apr 2025 09:47:40 +1000 Subject: [PATCH 61/76] refmt ruff Signed-off-by: George Mulhearn --- .../tests/test_default_verification_key_strategy.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/acapy_agent/wallet/tests/test_default_verification_key_strategy.py b/acapy_agent/wallet/tests/test_default_verification_key_strategy.py index 3d80443bb3..64649e72a0 100644 --- a/acapy_agent/wallet/tests/test_default_verification_key_strategy.py +++ b/acapy_agent/wallet/tests/test_default_verification_key_strategy.py @@ -13,6 +13,7 @@ TEST_DID_SOV = "did:sov:LjgpST2rjsoxYegQDRm7EL" TEST_DID_KEY = "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL" + class TestDefaultVerificationKeyStrategy(IsolatedAsyncioTestCase): async def asyncSetUp(self) -> None: self.profile = await create_test_profile() @@ -20,7 +21,7 @@ async def asyncSetUp(self) -> None: resolver.register_resolver( MockResolver( ["example"], - resolved= { + resolved={ "@context": [ "https://www.w3.org/ns/did/v1", "https://w3id.org/security/multikey/v1", @@ -48,7 +49,7 @@ async def asyncSetUp(self) -> None: ], "authentication": ["did:example:123#key-1"], "assertionMethod": ["did:example:123#key-2", "did:example:123#key-3"], - } + }, ) ) self.profile.context.injector.bind_instance(DIDResolver, resolver) @@ -74,7 +75,7 @@ async def test_with_did_for_assertion(self): "did:example:123", self.profile, proof_type="Ed25519Signature2020", - proof_purpose="assertionMethod" + proof_purpose="assertionMethod", ) == "did:example:123#key-2" ) @@ -83,7 +84,7 @@ async def test_with_did_for_assertion(self): "did:example:123", self.profile, proof_type="Ed25519Signature2018", - proof_purpose="assertionMethod" + proof_purpose="assertionMethod", ) == "did:example:123#key-3" ) From 94a2f2eda659d3cbc32d01f3b211910fab2efd69 Mon Sep 17 00:00:00 2001 From: David Chaiken Date: Wed, 2 Apr 2025 17:34:56 -0700 Subject: [PATCH 62/76] feat(demo): ngrok works with local docker environment Signed-off-by: David Chaiken --- demo/run_demo | 48 ++++++++++++++++++++++++++------- demo/runners/faber.py | 14 +++++----- docker/Dockerfile.demo | 3 +++ docs/demo/AliceGetsAPhone.md | 52 ++++++++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 15 deletions(-) diff --git a/demo/run_demo b/demo/run_demo index 49c32e2a11..e0a451bd23 100755 --- a/demo/run_demo +++ b/demo/run_demo @@ -221,17 +221,47 @@ else export RUNMODE="pwd" fi -# check if ngrok is running on our $AGENT_PORT (don't override if AGENT_ENDPOINT is already set) -if [ -z "$AGENT_ENDPOINT" ] && [ "$RUNMODE" == "docker" ]; then - echo "Trying to detect ngrok service endpoint" +if [ "$RUNMODE" == "docker" ]; then + echo "Checking ngrok service endpoints" JQ=${JQ:-`which jq`} if [ -x "$JQ" ]; then - NGROK_ENDPOINT=$(curl --silent localhost:4040/api/tunnels | $JQ -r '.tunnels[0].public_url') - if [ -z "$NGROK_ENDPOINT" ] || [ "$NGROK_ENDPOINT" = "null" ]; then - echo "ngrok not detected for agent endpoint" - else - export AGENT_ENDPOINT=$NGROK_ENDPOINT - echo "Detected ngrok agent endpoint [$AGENT_ENDPOINT]" + NGROK_CURL="curl --silent localhost:4040/api/tunnels" + # check if ngrok is running on our $AGENT_PORT (don't override if AGENT_ENDPOINT is already set) + if [ -z "$AGENT_ENDPOINT" ]; then + # default behavior is to use the first tunnel as the agent endpoint + NGROK_ENDPOINT=$($NGROK_CURL | $JQ -r '.tunnels[0].public_url') + # ngrok does not guarantee the order that the API returns the tunnels, + # so use the named endpoint if it exists. + NAMED_ENDPOINT=$($NGROK_CURL | $JQ -r '.tunnels[] | select(.name=="acapy-agent") | .public_url') + if ! [ -z "$NAMED_ENDPOINT" ]; then + NGROK_ENDPOINT=$NAMED_ENDPOINT # use the endpoint specified by name + fi + if [ -z "$NGROK_ENDPOINT" ] || [ "$NGROK_ENDPOINT" = "null" ]; then + echo "ngrok not detected for agent endpoint" + else + export AGENT_ENDPOINT=$NGROK_ENDPOINT + echo "Detected ngrok agent endpoint [$AGENT_ENDPOINT]" + fi + fi + # check if ngrok is running for webhooks (don't override if WEBHOOK_TARGET is already set) + if [ -z "$WEBHOOK_TARGET"]; then # webhook target not specified, see if ngrok lists it by name + NAMED_ENDPOINT=$($NGROK_CURL | $JQ -r '.tunnels[] | select(.name=="acapy-webhooks") | .public_url') + if [ -z "$NAMED_ENDPOINT" ]; then + echo "ngrok not detected for webhooks endpoint" + else + export WEBHOOK_TARGET=${NAMED_ENDPOINT}/webhooks + echo "Detected ngrok webhooks endpoint [$WEBHOOK_TARGET]" + fi + fi + # check if ngrok is running for tails-server (don't override if TAILS_NETWORK or PUBLIC_TAILS_URL is already set) + if [ -z "$TAILS_NETWORK" ] && [ -z "$PUBLIC_TAILS_URL" ]; then # tails-server not specified, see if ngrok lists it by name + NAMED_ENDPOINT=$($NGROK_CURL | $JQ -r '.tunnels[] | select(.name=="tails-server") | .public_url') + if [ -z "$NAMED_ENDPOINT" ]; then + echo "ngrok not detected for tails-server endpoint" + else + export PUBLIC_TAILS_URL=${NAMED_ENDPOINT} + echo "Detected ngrok tails-server endpoint [$PUBLIC_TAILS_URL]" + fi fi else echo "jq not found" diff --git a/demo/runners/faber.py b/demo/runners/faber.py index 765090a6dc..41948177f9 100644 --- a/demo/runners/faber.py +++ b/demo/runners/faber.py @@ -679,12 +679,14 @@ async def main(args): "/present-proof-2.0/create-request", proof_request_web_request ) pres_req_id = proof_request["pres_ex_id"] - url = ( - "http://" - + os.getenv("DOCKERHOST").replace( - "{PORT}", str(faber_agent.agent.admin_port + 1) - ) - + "/webhooks/pres_req/" + url = ((os.getenv("WEBHOOK_TARGET") or ( + "http://" + + os.getenv("DOCKERHOST").replace( + "{PORT}", str(faber_agent.agent.admin_port + 1) + ) + + "/webhooks" + )) + + "/pres_req/" + pres_req_id + "/" ) diff --git a/docker/Dockerfile.demo b/docker/Dockerfile.demo index 7d44dce3ac..dcc7ac2ee5 100644 --- a/docker/Dockerfile.demo +++ b/docker/Dockerfile.demo @@ -5,9 +5,12 @@ ENV ENABLE_PTVSD 0 ENV ENABLE_PYDEVD_PYCHARM 0 ENV PYDEVD_PYCHARM_HOST "host.docker.internal" +# jq is required for the ngrok-wait.sh script RUN mkdir -p bin && curl -L -o bin/jq \ https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 && \ chmod ug+x bin/jq +# some versions of docker put .local/bin in the PATH instead of bin +RUN mkdir -p .local/bin && ln -s ../../bin/jq .local/bin/jq # Copy and install Aries Agent code RUN pip install --no-cache-dir poetry==2.1.1 diff --git a/docs/demo/AliceGetsAPhone.md b/docs/demo/AliceGetsAPhone.md index 63045fd7b8..4cdfcccff5 100644 --- a/docs/demo/AliceGetsAPhone.md +++ b/docs/demo/AliceGetsAPhone.md @@ -115,6 +115,7 @@ git clone https://github.com/bcgov/indy-tails-server.git cd indy-tails-server/docker ./manage build ./manage start +./manage logs ``` This will run the required components for the tails server to function and make a tails server available on port 6543. @@ -128,12 +129,35 @@ ngrok-tails-server_1 | t=2020-05-13T22:51:14+0000 lvl=info msg="started tunnel" Note the server name in the `url=https://c5789aa0.ngrok.io` parameter (`https://c5789aa0.ngrok.io`) - this is the external url for your tails server. Make sure you use the `https` url! +If you see an "authentication failed" error in the logs like this: +```bash +ngrok-tails-server-1 | ERROR: authentication failed: Usage of ngrok requires a verified account and authtoken. +ngrok-tails-server-1 | ERROR: +ngrok-tails-server-1 | ERROR: Sign up for an account: https://dashboard.ngrok.com/signup +ngrok-tails-server-1 | ERROR: Install your authtoken: https://dashboard.ngrok.com/get-started/your-authtoken +``` +then you'll need to follow the links to set up a ngrok account and get an authentication token. +When you have the authtoken, hit CTRL-C to exit from the logs and run the following commands, +replacing `` with the authtoken from ngrok. +```bash +./manage logs # run above +^C +./manage stop +cat >>ngrok.yml +authtoken: +^D +./manage start +./manage logs +``` + #### Running in Play with Docker? Run the same steps on _PWD_ as you would run locally (see above). Open a new shell (click on "ADD NEW INSTANCE") to run the tails server. Note that with _Play with Docker_ it can be challenging to capture the information you need from the log file as it scrolls by, you can try leaving off the `--events` option when you run the Faber agent to reduce the quantity of information logged to the screen. +Also note that _PWD_ enviroments are insecure. If you enter a ngrok authtoken into a _PWD_ session, you should invalidate (reset) the authtoken as soon as you are done using the environment. + ### Run `faber` With Extra Parameters #### Running locally in a bash shell? @@ -218,6 +242,12 @@ http://ip10-0-121-4-bquqo816b480a4bfn3kg-8020.direct.play-with-docker.com?c_i=ey Note that this will use the ngrok endpoint if you are running locally, or your PWD endpoint if you are running on PWD. +When running locally, use the `AGENT_ENDPOINT` environment variable to run the demo so that it puts the public hostname in the QR code: +```bash +AGENT_ENDPOINT=https://abc123.ngrok.io LEDGER_URL=http://test.bcovrin.vonx.io ./run_demo faber +``` +See the Connectionless Proof Request section below for a more complete ngrok configuration that also supports the revocation option. + ## Issue a Credential We will use the Faber console to issue a credential. This could be done using the Swagger API as we have done in the connection process. We'll leave that as an exercise to the user. @@ -321,6 +351,28 @@ Then in the faber demo, select option `2a` - Faber will display a QR code which Behind the scenes, the Faber controller delivers the proof request information (linked from the url encoded in the QR code) directly to your mobile agent, without establishing and agent-to-agent connection first. If you are interested in the underlying mechanics, you can review the `faber.py` code in the repository. +If you want to use a connectionless proof request with docker running locally, you need to set up ngrok to forward both the agent port (8020) and the webhooks port (8022). If you have a free ngrok account, you need to run a single ngrok agent that forwards all of the necessary ports. Here is an ngrok configuration file that works for this purpose: +```yaml +version: "3" +agent: + authtoken: +tunnels: + acapy-agent: + proto: http + addr: 8020 + acapy-webhooks: + proto: http + addr: 8022 + tails-server: + addr: 6543 + inspect: false + proto: http +``` +When using this approach, leave your ngrok authtoken out of the tails-server ngrok.yml file to prevent the tails-server from starting its own ngrok agent. This trick avoids the following error from ngrok: +```bash +ERROR: authentication failed: Your account is limited to 1 simultaneous ngrok agent sessions. +``` + ## Conclusion That’s the Faber-Mobile Alice demo. Feel free to play with the Swagger API and experiment further and figure out what an instance of a controller has to do to make things work. From 864a3af8565ce90eab58916ff09783c0ad88e7bb Mon Sep 17 00:00:00 2001 From: Patrick St-Louis <43082425+PatStLouis@users.noreply.github.com> Date: Thu, 3 Apr 2025 14:42:21 -0400 Subject: [PATCH 63/76] Fetch existing invitation route (#3572) * fetch existing invitation route Signed-off-by: PatStLouis * lint Signed-off-by: PatStLouis * fetch by oob_id Signed-off-by: PatStLouis * linting Signed-off-by: PatStLouis * change to path parameter Signed-off-by: PatStLouis * return entire record Signed-off-by: PatStLouis * test new route and manager function Signed-off-by: PatStLouis * lint Signed-off-by: PatStLouis * fix tests Signed-off-by: PatStLouis * return class from function Signed-off-by: PatStLouis * add fn return type Signed-off-by: PatStLouis * add query parameter for oob_id and fix unit test Signed-off-by: PatStLouis --------- Signed-off-by: PatStLouis --- .../protocols/out_of_band/v1_0/manager.py | 15 +++++- .../protocols/out_of_band/v1_0/routes.py | 54 +++++++++++++++++++ .../out_of_band/v1_0/tests/test_manager.py | 33 ++++++++++++ .../out_of_band/v1_0/tests/test_routes.py | 21 ++++++++ 4 files changed, 121 insertions(+), 2 deletions(-) diff --git a/acapy_agent/protocols/out_of_band/v1_0/manager.py b/acapy_agent/protocols/out_of_band/v1_0/manager.py index ad7cf506e4..cef2b07e9a 100644 --- a/acapy_agent/protocols/out_of_band/v1_0/manager.py +++ b/acapy_agent/protocols/out_of_band/v1_0/manager.py @@ -1172,6 +1172,19 @@ async def delete_stale_connection_by_invitation(self, invi_msg_id: str): for conn_rec in conn_records: await conn_rec.delete_record(session) + async def fetch_oob_invitation_record_by_id(self, oob_id: str) -> OobRecord: + """Fetch oob_record associated with an oob_id.""" + async with self.profile.session() as session: + oob_record = await OobRecord.retrieve_by_id( + session, + record_id=oob_id, + ) + + if not oob_record: + raise StorageNotFoundError(f"No record found with oob_id {oob_id}") + + return oob_record + async def delete_conn_and_oob_record_invitation(self, invi_msg_id: str): """Delete conn_record and oob_record associated with an invi_msg_id.""" async with self.profile.session() as session: @@ -1180,7 +1193,6 @@ async def delete_conn_and_oob_record_invitation(self, invi_msg_id: str): tag_filter={ "invitation_msg_id": invi_msg_id, }, - post_filter_positive={}, ) for conn_rec in conn_records: await conn_rec.delete_record(session) @@ -1189,7 +1201,6 @@ async def delete_conn_and_oob_record_invitation(self, invi_msg_id: str): tag_filter={ "invi_msg_id": invi_msg_id, }, - post_filter_positive={}, ) for oob_rec in oob_records: await oob_rec.delete_record(session) diff --git a/acapy_agent/protocols/out_of_band/v1_0/routes.py b/acapy_agent/protocols/out_of_band/v1_0/routes.py index ced2c6694b..5826d9d1f5 100644 --- a/acapy_agent/protocols/out_of_band/v1_0/routes.py +++ b/acapy_agent/protocols/out_of_band/v1_0/routes.py @@ -35,6 +35,16 @@ class OutOfBandModuleResponseSchema(OpenAPISchema): """Response schema for Out of Band Module.""" +class OobIdQueryStringSchema(OpenAPISchema): + """Parameters and validators for fetch invitation request query string.""" + + oob_id = fields.Str( + required=True, + validate=UUID4_VALIDATE, + metadata={"description": "The Out of Band id to fetch"}, + ) + + class InvitationCreateQueryStringSchema(OpenAPISchema): """Parameters and validators for create invitation request query string.""" @@ -217,6 +227,45 @@ class InvitationRecordMatchInfoSchema(OpenAPISchema): ) +class OobInvitationRecordMatchInfoSchema(OpenAPISchema): + """Path parameters and validators for request taking invitation record.""" + + oob_id = fields.Str( + required=True, + validate=UUID4_VALIDATE, + metadata={ + "description": "OOB Invitation identifier", + "example": UUID4_EXAMPLE, + }, + ) + + +@docs(tags=["out-of-band"], summary="Fetch an existing Out-of-Band invitation.") +@querystring_schema(OobIdQueryStringSchema()) +@response_schema(InvitationRecordResponseSchema(), description="") +@tenant_authentication +async def invitation_fetch(request: web.BaseRequest): + """Request handler for fetching an invitation. + + Args: + request: aiohttp request object + + """ + context: AdminRequestContext = request["context"] + profile = context.profile + oob_mgr = OutOfBandManager(profile) + try: + record = await oob_mgr.fetch_oob_invitation_record_by_id( + request.query.get("oob_id") + ) + except StorageNotFoundError as err: + raise web.HTTPNotFound(reason=err.roll_up) from err + except StorageError as err: + raise web.HTTPBadRequest(reason=err.roll_up) from err + + return web.json_response(record.serialize()) + + @docs( tags=["out-of-band"], summary="Create a new connection invitation", @@ -365,6 +414,11 @@ async def register(app: web.Application): [ web.post("/out-of-band/create-invitation", invitation_create), web.post("/out-of-band/receive-invitation", invitation_receive), + web.get( + "/out-of-band/invitations", + invitation_fetch, + allow_head=False, + ), web.delete("/out-of-band/invitations/{invi_msg_id}", invitation_remove), ] ) diff --git a/acapy_agent/protocols/out_of_band/v1_0/tests/test_manager.py b/acapy_agent/protocols/out_of_band/v1_0/tests/test_manager.py index da4e43e43a..739edb73ff 100644 --- a/acapy_agent/protocols/out_of_band/v1_0/tests/test_manager.py +++ b/acapy_agent/protocols/out_of_band/v1_0/tests/test_manager.py @@ -1886,3 +1886,36 @@ async def test_delete_conn_and_oob_record_invitation(self): await self.manager.delete_conn_and_oob_record_invitation("test123") mock_connrecord_delete.assert_called_once() mock_oobrecord_delete.assert_called_once() + + async def test_fetch_invitation_succeeds(self): + self.profile.context.update_settings({"public_invites": True}) + + with mock.patch.object( + AskarWallet, "get_public_did", autospec=True + ) as mock_wallet_get_public_did: + mock_wallet_get_public_did.return_value = DIDInfo( + TestConfig.test_did, + TestConfig.test_verkey, + None, + method=SOV, + key_type=ED25519, + ) + invi_rec = await self.manager.create_invitation( + my_endpoint=TestConfig.test_endpoint, + public=True, + hs_protos=[HSProto.RFC23], + ) + + invi_rec = await self.manager.fetch_oob_invitation_record_by_id( + oob_id=invi_rec.oob_id + ) + + assert invi_rec.invitation._type == DIDCommPrefix.qualify_current( + self.TEST_INVI_MESSAGE_TYPE + ) + assert not invi_rec.invitation.requests_attach + assert ( + DIDCommPrefix.qualify_current(HSProto.RFC23.name) + in invi_rec.invitation.handshake_protocols + ) + assert invi_rec.invitation.services == [f"did:sov:{TestConfig.test_did}"] diff --git a/acapy_agent/protocols/out_of_band/v1_0/tests/test_routes.py b/acapy_agent/protocols/out_of_band/v1_0/tests/test_routes.py index 6e25915185..1c787f94f0 100644 --- a/acapy_agent/protocols/out_of_band/v1_0/tests/test_routes.py +++ b/acapy_agent/protocols/out_of_band/v1_0/tests/test_routes.py @@ -75,6 +75,27 @@ async def test_invitation_create(self): ) mock_json_response.assert_called_once_with({"abc": "123"}) + async def test_invitation_fetch(self): + self.request.query = {"oob_id": "dummy"} + + with ( + mock.patch.object( + test_module, "OutOfBandManager", autospec=True + ) as mock_oob_mgr, + mock.patch.object( + test_module.web, "json_response", mock.Mock() + ) as mock_json_response, + ): + mock_oob_mgr.return_value.fetch_oob_invitation_record_by_id = ( + mock.CoroutineMock( + return_value=mock.MagicMock( + serialize=mock.MagicMock(return_value={"abc": "123"}) + ) + ) + ) + await test_module.invitation_fetch(self.request) + mock_json_response.assert_called_once_with({"abc": "123"}) + async def test_invitation_remove(self): self.request.match_info = {"invi_msg_id": "dummy"} From 4b79670c49e4dbf2192e687958c54bf45c00e931 Mon Sep 17 00:00:00 2001 From: Stephen Curran Date: Thu, 3 Apr 2025 14:35:22 -0700 Subject: [PATCH 64/76] 1.3.0-rc1 (#3628) * 1.3.0-rc1 Signed-off-by: Stephen Curran * Add PR Signed-off-by: Stephen Curran --------- Signed-off-by: Stephen Curran --- CHANGELOG.md | 20 ++++-- Managing-ACA-Py-Doc-Site.md | 2 +- PUBLISHING.md | 4 +- docs/features/SupportedRFCs.md | 2 +- open-api/openapi.json | 122 +++++++++++++++++++++++++++++---- open-api/swagger.json | 120 ++++++++++++++++++++++++++++---- pyproject.toml | 2 +- 7 files changed, 236 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9290db9234..d0a69e0d9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,10 @@ # Aries Cloud Agent Python Changelog -## 1.3.0rc0 +## 1.3.0rc1 -### March 20, 2025 +### April 3, 2025 -Release 1.3.0 is a significant release that adds many updates, fixes and an important breaking change (starting to remove support for [AIP 1.0] from ACA-Py) from the 1.2.LTS branch of ACA-Py. The full list of changes are in in the [categorized list of pull requests](#130-categorized-list-of-pull-requests) for the release. As always, ACA-Py remains fully up to date with its dependencies. Fixes and improvements focused around the latest wallet type (`askar-anoncreds`), AnonCreds processing in general, and AnonCreds revocation in particular. +Release 1.3.0 is a significant release that adds many updates, fixes and an important breaking change (starting to remove support for [AIP 1.0] from ACA-Py) from the 1.2.LTS branch of ACA-Py. The full list of changes are in in the [categorized list of pull requests](#130-categorized-list-of-pull-requests) for the release. As always, ACA-Py remains fully up to date with its dependencies. Fixes and improvements focused around the latest wallet type (`askar-anoncreds`), AnonCreds processing in general, and AnonCreds revocation in particular. New to this release is a ACA-Py Helm Chart that can be used in deploying ACA-Py. ### 1.3.0 Deprecation Notices @@ -46,6 +46,10 @@ Specifics of the majority of the can be found by looking at the diffs for the `s - :art: Deprecate count/start query params and implement limit/offset [\#3208](https://github.com/openwallet-foundation/acapy/pull/3208) [ff137](https://github.com/ff137) - :sparkles: Add ordering options to askar scan and fetch_all methods [\#3173](https://github.com/openwallet-foundation/acapy/pull/3173) [ff137](https://github.com/ff137) - Updates/fixes to AnonCreds Processing + - :art: Use correct model for sending AnonCreds presentation [\#3618](https://github.com/openwallet-foundation/acapy/pull/3618) [ff137](https://github.com/ff137) + - fix: align ledger config schema with API response [\#3615](https://github.com/openwallet-foundation/acapy/pull/3615) [MonolithicMonk](https://github.com/MonolithicMonk) + - fix(ledger): correct response format for /ledger/get-write-ledgers endpoint [\#3613](https://github.com/openwallet-foundation/acapy/pull/3613) [MonolithicMonk](https://github.com/MonolithicMonk) + - :bug: Fix unchanged endpoint being rewritten to ledger [\#3608](https://github.com/openwallet-foundation/acapy/pull/3608) [ff137](https://github.com/ff137) - :bug: Fix auto creation of revocation registries [\#3601](https://github.com/openwallet-foundation/acapy/pull/3601) [ff137](https://github.com/ff137) - :sparkles: Refactor TailsServer injection pattern [\#3587](https://github.com/openwallet-foundation/acapy/pull/3587) [ff137](https://github.com/ff137) - :bug: Fix: Register both askar and anoncreds plugins for multitenancy [\#3585](https://github.com/openwallet-foundation/acapy/pull/3585) [ff137](https://github.com/ff137) @@ -66,9 +70,16 @@ Specifics of the majority of the can be found by looking at the diffs for the `s - Catch and log universal resolver setup error [\#3511](https://github.com/openwallet-foundation/acapy/pull/3511) [jamshale](https://github.com/jamshale) - W3C Verifiable Credentials Support Updates and Fixes: - Add vcdm 2.0 model and context [\#3436](https://github.com/openwallet-foundation/acapy/pull/3436) [PatStLouis](https://github.com/PatStLouis) +- DID Doc Handling Updates + - (fix) VM resolution strategy correction [\#3622](https://github.com/openwallet-foundation/acapy/pull/3622) [gmulhearn](https://github.com/gmulhearn) - DIDComm Protocol Updates and Fixes: + - Fetch existing invitation route [\#3572](https://github.com/openwallet-foundation/acapy/pull/3572) [PatStLouis](https://github.com/PatStLouis) - BREAKING: remove connection protocol [\#3184](https://github.com/openwallet-foundation/acapy/pull/3184) [dbluhm](https://github.com/dbluhm) - Documentation and Tutorial Pull Requests: + - feat(demo): remove broken aip 10 and fix aip 20 [\#3611](https://github.com/openwallet-foundation/acapy/pull/3611) [davidchaiken](https://github.com/davidchaiken) + - Fix demo implementation of vc_di cred issue [\#3609](https://github.com/openwallet-foundation/acapy/pull/3609) [ianco](https://github.com/ianco) + - chore(demo): remove aip 10 code [\#3619](https://github.com/openwallet-foundation/acapy/pull/3619) [davidchaiken](https://github.com/davidchaiken) + - Create Acapy Helm Chart [\#3599](https://github.com/openwallet-foundation/acapy/pull/3599) [i5okie](https://github.com/i5okie) - :memo: Update README [\#3588](https://github.com/openwallet-foundation/acapy/pull/3588) [ff137](https://github.com/ff137) - Fix missing log_timer import in acme.py [\#3562](https://github.com/openwallet-foundation/acapy/pull/3562) [parth5805](https://github.com/parth5805) - Fix prompt for alice/faber demo [\#3553](https://github.com/openwallet-foundation/acapy/pull/3553) [ianco](https://github.com/ianco) @@ -98,9 +109,10 @@ Specifics of the majority of the can be found by looking at the diffs for the `s - Update dockerfile image after release [\#3469](https://github.com/openwallet-foundation/acapy/pull/3469) [jamshale](https://github.com/jamshale) - :arrow_up: Upgrade dependencies [\#3455](https://github.com/openwallet-foundation/acapy/pull/3455) [ff137](https://github.com/ff137) - Release management pull requests: + - 1.3.0rc1 [\#3628](https://github.com/openwallet-foundation/acapy/pull/3628) [swcurran](https://github.com/swcurran) - 1.3.0rc0 [\#3604](https://github.com/openwallet-foundation/acapy/pull/3604) [swcurran](https://github.com/swcurran) - Dependabot PRs - - [Link to list of Dependabot PRs in this release](https://github.com/openwallet-foundation/acapy/pulls?q=is%3Apr+is%3Amerged+merged%3A2025-01-21..2025-03-19+author%3Aapp%2Fdependabot+) + - [Link to list of Dependabot PRs in this release](https://github.com/openwallet-foundation/acapy/pulls?q=is%3Apr+is%3Amerged+merged%3A2025-01-21..2025-04-03+author%3Aapp%2Fdependabot+) ## 1.2.4 diff --git a/Managing-ACA-Py-Doc-Site.md b/Managing-ACA-Py-Doc-Site.md index ba5c9ebcab..ed9722d102 100644 --- a/Managing-ACA-Py-Doc-Site.md +++ b/Managing-ACA-Py-Doc-Site.md @@ -97,7 +97,7 @@ To delete the documentation version, do the following: - Check your `git status` and make sure there are no changes in the branch -- e.g., new files that shouldn't be added to the `gh-pages` branch. If there are any -- delete the files so they are not added. -- Remove the folder for the RC. For example `rm -rf 1.3.0rc0` +- Remove the folder for the RC. For example `rm -rf 1.3.0rc1` - Edit the `versions.json` file and remove the reference to the RC release in the file. - Push the changes via a PR to the ACA-Py `gh-pages` branch (don't PR them into diff --git a/PUBLISHING.md b/PUBLISHING.md index 26dd39f773..1fced634b3 100644 --- a/PUBLISHING.md +++ b/PUBLISHING.md @@ -6,7 +6,7 @@ a major, minor or patch release, per [semver](https://semver.org/) rules. Once ready to do a release, create a local branch that includes the following updates: -1. Create a local PR branch from an updated `main` branch, e.g. "1.3.0rc0". +1. Create a local PR branch from an updated `main` branch, e.g. "1.3.0rc1". 2. See if there are any Document Site `mkdocs` changes needed. Run the script `./scripts/prepmkdocs.sh; mkdocs`. Watch the log, noting particularly if @@ -140,7 +140,7 @@ Once you have the list of PRs: [publish-indy.yml]: https://github.com/openwallet-foundation/acapy/blob/main/.github/workflows/publish-indy.yml 12. When a new release is tagged, create a new branch at the same commit with - the branch name in the format `docs-v`, for example, `docs-v1.3.0rc0`. + the branch name in the format `docs-v`, for example, `docs-v1.3.0rc1`. The creation of the branch triggers the execution of the [publish-docs] GitHub Action which generates the documentation for the new release, publishing it at [https://aca-py.org]. The GitHub Action also executes when diff --git a/docs/features/SupportedRFCs.md b/docs/features/SupportedRFCs.md index ba9b69e263..a7082dffb3 100644 --- a/docs/features/SupportedRFCs.md +++ b/docs/features/SupportedRFCs.md @@ -8,7 +8,7 @@ ACA-Py or the repository `main` branch. Reminders (and PRs!) to update this page welcome! If you have any questions, please contact us on the #aries channel on [OpenWallet Foundation Discord](https://discord.gg/openwallet-foundation) or through an issue in this repo. -**Last Update**: 2025-03-20, Release 1.3.0rc0 +**Last Update**: 2025-04-03, Release 1.3.0rc1 > The checklist version of this document was created as a joint effort > between [Northern Block](https://northernblock.io/), [Animo Solutions](https://animo.id/) and the Ontario government, on behalf of the Ontario government. diff --git a/open-api/openapi.json b/open-api/openapi.json index 7f0e57e9a0..6febd23147 100644 --- a/open-api/openapi.json +++ b/open-api/openapi.json @@ -2,7 +2,7 @@ "openapi" : "3.0.1", "info" : { "title" : "Aries Cloud Agent", - "version" : "v1.3.0rc0" + "version" : "v1.3.0rc1" }, "servers" : [ { "url" : "/" @@ -7781,6 +7781,40 @@ "required" : [ "attrNames", "issuerId", "name", "version" ], "type" : "object" }, + "AnoncredsPresSpec" : { + "properties" : { + "requested_attributes" : { + "additionalProperties" : { + "$ref" : "#/components/schemas/AnoncredsRequestedCredsRequestedAttr" + }, + "description" : "Nested object mapping proof request attribute referents to requested-attribute specifiers", + "type" : "object" + }, + "requested_predicates" : { + "additionalProperties" : { + "$ref" : "#/components/schemas/AnoncredsRequestedCredsRequestedPred" + }, + "description" : "Nested object mapping proof request predicate referents to requested-predicate specifiers", + "type" : "object" + }, + "self_attested_attributes" : { + "additionalProperties" : { + "description" : "Self-attested attribute values to use in requested-credentials structure for proof construction", + "example" : "self_attested_value", + "type" : "string" + }, + "description" : "Self-attested attributes to build into proof", + "type" : "object" + }, + "trace" : { + "description" : "Whether to trace event (default false)", + "example" : false, + "type" : "boolean" + } + }, + "required" : [ "requested_attributes", "requested_predicates", "self_attested_attributes" ], + "type" : "object" + }, "AnoncredsPresentationReqAttrSpec" : { "properties" : { "name" : { @@ -7945,6 +7979,39 @@ }, "type" : "object" }, + "AnoncredsRequestedCredsRequestedAttr" : { + "properties" : { + "cred_id" : { + "description" : "Wallet credential identifier (typically but not necessarily a UUID)", + "example" : "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "type" : "string" + }, + "revealed" : { + "description" : "Whether to reveal attribute in proof (default true)", + "type" : "boolean" + } + }, + "required" : [ "cred_id" ], + "type" : "object" + }, + "AnoncredsRequestedCredsRequestedPred" : { + "properties" : { + "cred_id" : { + "description" : "Wallet credential identifier (typically but not necessarily a UUID)", + "example" : "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "type" : "string" + }, + "timestamp" : { + "description" : "Epoch timestamp of interest for non-revocation proof", + "example" : 1640995199, + "maximum" : 18446744073709551615, + "minimum" : 0, + "type" : "integer" + } + }, + "required" : [ "cred_id" ], + "type" : "object" + }, "AnoncredsRevocationModuleResponse" : { "type" : "object" }, @@ -12030,39 +12097,66 @@ }, "LedgerConfigInstance" : { "properties" : { - "genesis_file" : { - "description" : "genesis_file", - "type" : "string" - }, - "genesis_transactions" : { - "description" : "genesis_transactions", + "endorser_alias" : { + "description" : "Endorser service alias (optional)", "type" : "string" }, - "genesis_url" : { - "description" : "genesis_url", + "endorser_did" : { + "description" : "Endorser DID (optional)", "type" : "string" }, "id" : { - "description" : "ledger_id", + "description" : "Ledger identifier. Auto-generated UUID4 if not provided", + "example" : "f47ac10b-58cc-4372-a567-0e02b2c3d479", "type" : "string" }, "is_production" : { - "description" : "is_production", + "description" : "Production-grade ledger (true/false)", + "type" : "boolean" + }, + "is_write" : { + "description" : "Write capability enabled (default: False)", + "type" : "boolean" + }, + "keepalive" : { + "description" : "Keep-alive timeout in seconds for idle connections", + "type" : "integer" + }, + "pool_name" : { + "description" : "Ledger pool name (defaults to ledger ID if not specified)", + "example" : "bcovrin-test-pool", + "type" : "string" + }, + "read_only" : { + "description" : "Read-only access (default: False)", "type" : "boolean" + }, + "socks_proxy" : { + "description" : "SOCKS proxy URL (optional)", + "type" : "string" } }, + "required" : [ "id", "is_production" ], "type" : "object" }, "LedgerConfigList" : { "properties" : { - "ledger_config_list" : { + "non_production_ledgers" : { + "description" : "Non-production ledgers (may be empty)", + "items" : { + "$ref" : "#/components/schemas/LedgerConfigInstance" + }, + "type" : "array" + }, + "production_ledgers" : { + "description" : "Production ledgers (may be empty)", "items" : { "$ref" : "#/components/schemas/LedgerConfigInstance" }, "type" : "array" } }, - "required" : [ "ledger_config_list" ], + "required" : [ "non_production_ledgers", "production_ledgers" ], "type" : "object" }, "LedgerModulesResult" : { @@ -16631,7 +16725,7 @@ "properties" : { "anoncreds" : { "allOf" : [ { - "$ref" : "#/components/schemas/IndyPresSpec" + "$ref" : "#/components/schemas/AnoncredsPresSpec" } ], "description" : "Presentation specification for anoncreds", "type" : "object" diff --git a/open-api/swagger.json b/open-api/swagger.json index 74b1c839e3..fce01ff1c2 100644 --- a/open-api/swagger.json +++ b/open-api/swagger.json @@ -1,7 +1,7 @@ { "swagger" : "2.0", "info" : { - "version" : "v1.3.0rc0", + "version" : "v1.3.0rc1", "title" : "Aries Cloud Agent" }, "tags" : [ { @@ -6410,6 +6410,40 @@ } } }, + "AnoncredsPresSpec" : { + "type" : "object", + "required" : [ "requested_attributes", "requested_predicates", "self_attested_attributes" ], + "properties" : { + "requested_attributes" : { + "type" : "object", + "description" : "Nested object mapping proof request attribute referents to requested-attribute specifiers", + "additionalProperties" : { + "$ref" : "#/definitions/AnoncredsRequestedCredsRequestedAttr" + } + }, + "requested_predicates" : { + "type" : "object", + "description" : "Nested object mapping proof request predicate referents to requested-predicate specifiers", + "additionalProperties" : { + "$ref" : "#/definitions/AnoncredsRequestedCredsRequestedPred" + } + }, + "self_attested_attributes" : { + "type" : "object", + "description" : "Self-attested attributes to build into proof", + "additionalProperties" : { + "type" : "string", + "example" : "self_attested_value", + "description" : "Self-attested attribute values to use in requested-credentials structure for proof construction" + } + }, + "trace" : { + "type" : "boolean", + "example" : false, + "description" : "Whether to trace event (default false)" + } + } + }, "AnoncredsPresentationReqAttrSpec" : { "type" : "object", "properties" : { @@ -6574,6 +6608,39 @@ } } }, + "AnoncredsRequestedCredsRequestedAttr" : { + "type" : "object", + "required" : [ "cred_id" ], + "properties" : { + "cred_id" : { + "type" : "string", + "example" : "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "description" : "Wallet credential identifier (typically but not necessarily a UUID)" + }, + "revealed" : { + "type" : "boolean", + "description" : "Whether to reveal attribute in proof (default true)" + } + } + }, + "AnoncredsRequestedCredsRequestedPred" : { + "type" : "object", + "required" : [ "cred_id" ], + "properties" : { + "cred_id" : { + "type" : "string", + "example" : "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "description" : "Wallet credential identifier (typically but not necessarily a UUID)" + }, + "timestamp" : { + "type" : "integer", + "example" : 1640995199, + "description" : "Epoch timestamp of interest for non-revocation proof", + "minimum" : 0, + "maximum" : 18446744073709551615 + } + } + }, "AnoncredsRevocationModuleResponse" : { "type" : "object" }, @@ -10389,35 +10456,62 @@ }, "LedgerConfigInstance" : { "type" : "object", + "required" : [ "id", "is_production" ], "properties" : { - "genesis_file" : { + "endorser_alias" : { "type" : "string", - "description" : "genesis_file" + "description" : "Endorser service alias (optional)" }, - "genesis_transactions" : { - "type" : "string", - "description" : "genesis_transactions" - }, - "genesis_url" : { + "endorser_did" : { "type" : "string", - "description" : "genesis_url" + "description" : "Endorser DID (optional)" }, "id" : { "type" : "string", - "description" : "ledger_id" + "example" : "f47ac10b-58cc-4372-a567-0e02b2c3d479", + "description" : "Ledger identifier. Auto-generated UUID4 if not provided" }, "is_production" : { "type" : "boolean", - "description" : "is_production" + "description" : "Production-grade ledger (true/false)" + }, + "is_write" : { + "type" : "boolean", + "description" : "Write capability enabled (default: False)" + }, + "keepalive" : { + "type" : "integer", + "description" : "Keep-alive timeout in seconds for idle connections" + }, + "pool_name" : { + "type" : "string", + "example" : "bcovrin-test-pool", + "description" : "Ledger pool name (defaults to ledger ID if not specified)" + }, + "read_only" : { + "type" : "boolean", + "description" : "Read-only access (default: False)" + }, + "socks_proxy" : { + "type" : "string", + "description" : "SOCKS proxy URL (optional)" } } }, "LedgerConfigList" : { "type" : "object", - "required" : [ "ledger_config_list" ], + "required" : [ "non_production_ledgers", "production_ledgers" ], "properties" : { - "ledger_config_list" : { + "non_production_ledgers" : { + "type" : "array", + "description" : "Non-production ledgers (may be empty)", + "items" : { + "$ref" : "#/definitions/LedgerConfigInstance" + } + }, + "production_ledgers" : { "type" : "array", + "description" : "Production ledgers (may be empty)", "items" : { "$ref" : "#/definitions/LedgerConfigInstance" } diff --git a/pyproject.toml b/pyproject.toml index 24c1f3d935..aed53dca86 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "acapy_agent" -version = "1.3.0rc0" +version = "1.3.0rc1" description = "(ACA-Py) A Cloud Agent Python is a foundation for building decentralized identity applications and services running in non-mobile environments. " authors = [] license = "Apache-2.0" From ea1d7d398b8cb89fbcf568207f5511477b537ca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emiliano=20Su=C3=B1=C3=A9?= Date: Sat, 5 Apr 2025 06:12:03 -0700 Subject: [PATCH 65/76] Devcointainer and docs update (#3629) --- .devcontainer/devcontainer.json | 3 +-- docs/deploying/AnoncredsControllerMigration.md | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 311afbdf9b..744587ae9a 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -39,8 +39,7 @@ "enable": true }, "ruff.fixAll": true, - "ruff.format.args": ["--config=./pyproject.toml"], - "ruff.lint.args": ["--config=./pyproject.toml"] + "ruff.configuration": "~/.config/pyproject.toml" } } }, diff --git a/docs/deploying/AnoncredsControllerMigration.md b/docs/deploying/AnoncredsControllerMigration.md index f2ebd203cb..aa8252a0ee 100644 --- a/docs/deploying/AnoncredsControllerMigration.md +++ b/docs/deploying/AnoncredsControllerMigration.md @@ -653,7 +653,7 @@ to The upgrade endpoint is at **POST /anoncreds/wallet/upgrade**. -You need to be careful doing this, as there is no way to downgrade the wallet. It is recommended highly recommended to back-up any wallets and to test the upgrade in a development environment before upgrading a production wallet. +You need to be careful doing this, as there is no way to downgrade the wallet. It is highly recommended to back-up any wallets and to test the upgrade in a development environment before upgrading a production wallet. Params: `wallet_name` is the name of the wallet to upgrade. Used to prevent accidental upgrades. @@ -670,6 +670,8 @@ The agent will get a 503 error during the upgrade process. Any agent instance wi The aca-py agent will work after the restart. However, it will receive a warning for having the wrong wallet type configured. It is recommended to change the `wallet-type` to `askar-anoncreds` in the agent configuration file or start-up command. +**Note:** when in a multitenant mode, it is recommended to upgrade the admin wallet *before* the sub-wallets, as this will ensire new sub-wallets will be created using the `askar-anoncreds` wallet type. In order to invoke the upgrade endpoint for the admin wallet, the path `/anoncreds/wallet/upgrade` muse be "enabled" by adding it to the `base-wallet-paths` setting. + ### Subwallet (tenant) in multitenancy mode -The sub-tenant which is in the process of being upgraded will get a 503 error during the upgrade process. All other sub-tenants will continue to operate normally. After the upgrade is complete the sub-tenant will be able to use the new endpoints. The old endpoints will no longer be available and result in a 403 error. Any aca-py agents will remain running after the upgrade and it's not required that the aca-py agent restarts. +The sub-tenant which is in the process of being upgraded will get a 503 error during the upgrade process. All other sub-tenants will continue to operate normally. After the upgrade is complete the sub-tenant will be able to use the new endpoints. The old endpoints will no longer be available and result in a 403 error. Any aca-py agents will remain running after the upgrade and it's not required that the aca-py agent restarts. From 246af2c79f1f09d0050e9e694090dc7dc2fa4f0c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 17:18:58 +0000 Subject: [PATCH 66/76] chore(deps-dev): Bump pytest-cov from 6.0.0 to 6.1.1 (#3631) --- poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index e4a3ba1a1d..41b3adabcb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2399,14 +2399,14 @@ testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] [[package]] name = "pytest-cov" -version = "6.0.0" +version = "6.1.1" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"}, - {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"}, + {file = "pytest_cov-6.1.1-py3-none-any.whl", hash = "sha256:bddf29ed2d0ab6f4df17b4c55b0a657287db8684af9c42ea546b21b1041b3dde"}, + {file = "pytest_cov-6.1.1.tar.gz", hash = "sha256:46935f7aaefba760e716c2ebfbe1c216240b9592966e7da99ea8292d4d3e2a0a"}, ] [package.dependencies] From 12f44b43462ddf1a1739d7197ab18f6859240b3b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 09:34:51 +0000 Subject: [PATCH 67/76] chore(deps): Bump tj-actions/changed-files in the all-actions group (#3635) --- .github/workflows/bdd-integration-tests.yml | 2 +- .github/workflows/bdd-interop-tests.yml | 2 +- .github/workflows/scenario-integration-tests.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/bdd-integration-tests.yml b/.github/workflows/bdd-integration-tests.yml index 6960f9e208..dab42ab1ac 100644 --- a/.github/workflows/bdd-integration-tests.yml +++ b/.github/workflows/bdd-integration-tests.yml @@ -31,7 +31,7 @@ jobs: fetch-depth: 0 - name: Check changed files id: check-changed-files - uses: tj-actions/changed-files@v46.0.3 + uses: tj-actions/changed-files@v46.0.4 with: files_yaml: | src: diff --git a/.github/workflows/bdd-interop-tests.yml b/.github/workflows/bdd-interop-tests.yml index b24d6530f2..a70a03ea4c 100644 --- a/.github/workflows/bdd-interop-tests.yml +++ b/.github/workflows/bdd-interop-tests.yml @@ -31,7 +31,7 @@ jobs: fetch-depth: 0 - name: Check changed files id: check-changed-files - uses: tj-actions/changed-files@v46.0.3 + uses: tj-actions/changed-files@v46.0.4 with: files_yaml: | src: diff --git a/.github/workflows/scenario-integration-tests.yml b/.github/workflows/scenario-integration-tests.yml index 6406bd20d3..4e9c6c7a01 100644 --- a/.github/workflows/scenario-integration-tests.yml +++ b/.github/workflows/scenario-integration-tests.yml @@ -29,7 +29,7 @@ jobs: fetch-depth: 0 - name: Check changed files id: check-changed-files - uses: tj-actions/changed-files@v46.0.3 + uses: tj-actions/changed-files@v46.0.4 with: files_yaml: | scenarios: "scenarios/**/*" From 62e8eecf34e4484578caea97436f555fe8cd0af2 Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Tue, 8 Apr 2025 13:24:54 +0200 Subject: [PATCH 68/76] :arrow_up: Weekly dependency updates (#3634) * :arrow_up: Weekly dependency updates Minor bump to qrcode, and patch upgrades for: aiohttp, aries-askar, pydantic, ruff Signed-off-by: ff137 * :recycle: Sync ruff version Signed-off-by: ff137 --------- Signed-off-by: ff137 Co-authored-by: Stephen Curran --- .github/workflows/format.yml | 2 +- .pre-commit-config.yaml | 2 +- poetry.lock | 1506 +++++++++++++++++----------------- pyproject.toml | 6 +- 4 files changed, 767 insertions(+), 749 deletions(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 3b00c7d47a..df8efffebf 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -17,5 +17,5 @@ jobs: - name: Ruff Format and Lint Check uses: chartboost/ruff-action@v1 with: - version: 0.11.0 + version: 0.11.4 args: "format --check" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ae43b0525c..7abad067b2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,7 +8,7 @@ repos: additional_dependencies: ['@commitlint/config-conventional'] - repo: https://github.com/astral-sh/ruff-pre-commit # Ensure this is synced with pyproject.toml - rev: v0.11.0 + rev: v0.11.4 hooks: # Run the linter - id: ruff diff --git a/poetry.lock b/poetry.lock index 41b3adabcb..4d376660ad 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -14,93 +14,93 @@ files = [ [[package]] name = "aiohttp" -version = "3.11.13" +version = "3.11.16" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohttp-3.11.13-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a4fe27dbbeec445e6e1291e61d61eb212ee9fed6e47998b27de71d70d3e8777d"}, - {file = "aiohttp-3.11.13-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9e64ca2dbea28807f8484c13f684a2f761e69ba2640ec49dacd342763cc265ef"}, - {file = "aiohttp-3.11.13-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9840be675de208d1f68f84d578eaa4d1a36eee70b16ae31ab933520c49ba1325"}, - {file = "aiohttp-3.11.13-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28a772757c9067e2aee8a6b2b425d0efaa628c264d6416d283694c3d86da7689"}, - {file = "aiohttp-3.11.13-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b88aca5adbf4625e11118df45acac29616b425833c3be7a05ef63a6a4017bfdb"}, - {file = "aiohttp-3.11.13-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ce10ddfbe26ed5856d6902162f71b8fe08545380570a885b4ab56aecfdcb07f4"}, - {file = "aiohttp-3.11.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa48dac27f41b36735c807d1ab093a8386701bbf00eb6b89a0f69d9fa26b3671"}, - {file = "aiohttp-3.11.13-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89ce611b1eac93ce2ade68f1470889e0173d606de20c85a012bfa24be96cf867"}, - {file = "aiohttp-3.11.13-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:78e4dd9c34ec7b8b121854eb5342bac8b02aa03075ae8618b6210a06bbb8a115"}, - {file = "aiohttp-3.11.13-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:66047eacbc73e6fe2462b77ce39fc170ab51235caf331e735eae91c95e6a11e4"}, - {file = "aiohttp-3.11.13-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5ad8f1c19fe277eeb8bc45741c6d60ddd11d705c12a4d8ee17546acff98e0802"}, - {file = "aiohttp-3.11.13-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64815c6f02e8506b10113ddbc6b196f58dbef135751cc7c32136df27b736db09"}, - {file = "aiohttp-3.11.13-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:967b93f21b426f23ca37329230d5bd122f25516ae2f24a9cea95a30023ff8283"}, - {file = "aiohttp-3.11.13-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cf1f31f83d16ec344136359001c5e871915c6ab685a3d8dee38e2961b4c81730"}, - {file = "aiohttp-3.11.13-cp310-cp310-win32.whl", hash = "sha256:00c8ac69e259c60976aa2edae3f13d9991cf079aaa4d3cd5a49168ae3748dee3"}, - {file = "aiohttp-3.11.13-cp310-cp310-win_amd64.whl", hash = "sha256:90d571c98d19a8b6e793b34aa4df4cee1e8fe2862d65cc49185a3a3d0a1a3996"}, - {file = "aiohttp-3.11.13-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b35aab22419ba45f8fc290d0010898de7a6ad131e468ffa3922b1b0b24e9d2e"}, - {file = "aiohttp-3.11.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81cba651db8795f688c589dd11a4fbb834f2e59bbf9bb50908be36e416dc760"}, - {file = "aiohttp-3.11.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f55d0f242c2d1fcdf802c8fabcff25a9d85550a4cf3a9cf5f2a6b5742c992839"}, - {file = "aiohttp-3.11.13-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4bea08a6aad9195ac9b1be6b0c7e8a702a9cec57ce6b713698b4a5afa9c2e33"}, - {file = "aiohttp-3.11.13-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6070bcf2173a7146bb9e4735b3c62b2accba459a6eae44deea0eb23e0035a23"}, - {file = "aiohttp-3.11.13-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:718d5deb678bc4b9d575bfe83a59270861417da071ab44542d0fcb6faa686636"}, - {file = "aiohttp-3.11.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f6b2c5b4a4d22b8fb2c92ac98e0747f5f195e8e9448bfb7404cd77e7bfa243f"}, - {file = "aiohttp-3.11.13-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:747ec46290107a490d21fe1ff4183bef8022b848cf9516970cb31de6d9460088"}, - {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:01816f07c9cc9d80f858615b1365f8319d6a5fd079cd668cc58e15aafbc76a54"}, - {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a08ad95fcbd595803e0c4280671d808eb170a64ca3f2980dd38e7a72ed8d1fea"}, - {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c97be90d70f7db3aa041d720bfb95f4869d6063fcdf2bb8333764d97e319b7d0"}, - {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ab915a57c65f7a29353c8014ac4be685c8e4a19e792a79fe133a8e101111438e"}, - {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:35cda4e07f5e058a723436c4d2b7ba2124ab4e0aa49e6325aed5896507a8a42e"}, - {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:af55314407714fe77a68a9ccaab90fdb5deb57342585fd4a3a8102b6d4370080"}, - {file = "aiohttp-3.11.13-cp311-cp311-win32.whl", hash = "sha256:42d689a5c0a0c357018993e471893e939f555e302313d5c61dfc566c2cad6185"}, - {file = "aiohttp-3.11.13-cp311-cp311-win_amd64.whl", hash = "sha256:b73a2b139782a07658fbf170fe4bcdf70fc597fae5ffe75e5b67674c27434a9f"}, - {file = "aiohttp-3.11.13-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2eabb269dc3852537d57589b36d7f7362e57d1ece308842ef44d9830d2dc3c90"}, - {file = "aiohttp-3.11.13-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b77ee42addbb1c36d35aca55e8cc6d0958f8419e458bb70888d8c69a4ca833d"}, - {file = "aiohttp-3.11.13-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55789e93c5ed71832e7fac868167276beadf9877b85697020c46e9a75471f55f"}, - {file = "aiohttp-3.11.13-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c929f9a7249a11e4aa5c157091cfad7f49cc6b13f4eecf9b747104befd9f56f2"}, - {file = "aiohttp-3.11.13-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d33851d85537bbf0f6291ddc97926a754c8f041af759e0aa0230fe939168852b"}, - {file = "aiohttp-3.11.13-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9229d8613bd8401182868fe95688f7581673e1c18ff78855671a4b8284f47bcb"}, - {file = "aiohttp-3.11.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:669dd33f028e54fe4c96576f406ebb242ba534dd3a981ce009961bf49960f117"}, - {file = "aiohttp-3.11.13-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c1b20a1ace54af7db1f95af85da530fe97407d9063b7aaf9ce6a32f44730778"}, - {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5724cc77f4e648362ebbb49bdecb9e2b86d9b172c68a295263fa072e679ee69d"}, - {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:aa36c35e94ecdb478246dd60db12aba57cfcd0abcad43c927a8876f25734d496"}, - {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9b5b37c863ad5b0892cc7a4ceb1e435e5e6acd3f2f8d3e11fa56f08d3c67b820"}, - {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e06cf4852ce8c4442a59bae5a3ea01162b8fcb49ab438d8548b8dc79375dad8a"}, - {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5194143927e494616e335d074e77a5dac7cd353a04755330c9adc984ac5a628e"}, - {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:afcb6b275c2d2ba5d8418bf30a9654fa978b4f819c2e8db6311b3525c86fe637"}, - {file = "aiohttp-3.11.13-cp312-cp312-win32.whl", hash = "sha256:7104d5b3943c6351d1ad7027d90bdd0ea002903e9f610735ac99df3b81f102ee"}, - {file = "aiohttp-3.11.13-cp312-cp312-win_amd64.whl", hash = "sha256:47dc018b1b220c48089b5b9382fbab94db35bef2fa192995be22cbad3c5730c8"}, - {file = "aiohttp-3.11.13-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9862d077b9ffa015dbe3ce6c081bdf35135948cb89116e26667dd183550833d1"}, - {file = "aiohttp-3.11.13-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fbfef0666ae9e07abfa2c54c212ac18a1f63e13e0760a769f70b5717742f3ece"}, - {file = "aiohttp-3.11.13-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:93a1f7d857c4fcf7cabb1178058182c789b30d85de379e04f64c15b7e88d66fb"}, - {file = "aiohttp-3.11.13-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba40b7ae0f81c7029583a338853f6607b6d83a341a3dcde8bed1ea58a3af1df9"}, - {file = "aiohttp-3.11.13-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5b95787335c483cd5f29577f42bbe027a412c5431f2f80a749c80d040f7ca9f"}, - {file = "aiohttp-3.11.13-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7d474c5c1f0b9405c1565fafdc4429fa7d986ccbec7ce55bc6a330f36409cad"}, - {file = "aiohttp-3.11.13-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e83fb1991e9d8982b3b36aea1e7ad27ea0ce18c14d054c7a404d68b0319eebb"}, - {file = "aiohttp-3.11.13-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4586a68730bd2f2b04a83e83f79d271d8ed13763f64b75920f18a3a677b9a7f0"}, - {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fe4eb0e7f50cdb99b26250d9328faef30b1175a5dbcfd6d0578d18456bac567"}, - {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2a8a6bc19818ac3e5596310ace5aa50d918e1ebdcc204dc96e2f4d505d51740c"}, - {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7f27eec42f6c3c1df09cfc1f6786308f8b525b8efaaf6d6bd76c1f52c6511f6a"}, - {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:2a4a13dfbb23977a51853b419141cd0a9b9573ab8d3a1455c6e63561387b52ff"}, - {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:02876bf2f69b062584965507b07bc06903c2dc93c57a554b64e012d636952654"}, - {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b992778d95b60a21c4d8d4a5f15aaab2bd3c3e16466a72d7f9bfd86e8cea0d4b"}, - {file = "aiohttp-3.11.13-cp313-cp313-win32.whl", hash = "sha256:507ab05d90586dacb4f26a001c3abf912eb719d05635cbfad930bdbeb469b36c"}, - {file = "aiohttp-3.11.13-cp313-cp313-win_amd64.whl", hash = "sha256:5ceb81a4db2decdfa087381b5fc5847aa448244f973e5da232610304e199e7b2"}, - {file = "aiohttp-3.11.13-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:51c3ff9c7a25f3cad5c09d9aacbc5aefb9267167c4652c1eb737989b554fe278"}, - {file = "aiohttp-3.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e271beb2b1dabec5cd84eb488bdabf9758d22ad13471e9c356be07ad139b3012"}, - {file = "aiohttp-3.11.13-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0e9eb7e5764abcb49f0e2bd8f5731849b8728efbf26d0cac8e81384c95acec3f"}, - {file = "aiohttp-3.11.13-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baae005092e3f200de02699314ac8933ec20abf998ec0be39448f6605bce93df"}, - {file = "aiohttp-3.11.13-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1982c98ac62c132d2b773d50e2fcc941eb0b8bad3ec078ce7e7877c4d5a2dce7"}, - {file = "aiohttp-3.11.13-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2b25b2eeb35707113b2d570cadc7c612a57f1c5d3e7bb2b13870fe284e08fc0"}, - {file = "aiohttp-3.11.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b27961d65639128336b7a7c3f0046dcc62a9443d5ef962e3c84170ac620cec47"}, - {file = "aiohttp-3.11.13-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a01fe9f1e05025eacdd97590895e2737b9f851d0eb2e017ae9574d9a4f0b6252"}, - {file = "aiohttp-3.11.13-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa1fb1b61881c8405829c50e9cc5c875bfdbf685edf57a76817dfb50643e4a1a"}, - {file = "aiohttp-3.11.13-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:25de43bb3cf83ad83efc8295af7310219af6dbe4c543c2e74988d8e9c8a2a917"}, - {file = "aiohttp-3.11.13-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fe7065e2215e4bba63dc00db9ae654c1ba3950a5fff691475a32f511142fcddb"}, - {file = "aiohttp-3.11.13-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:7836587eef675a17d835ec3d98a8c9acdbeb2c1d72b0556f0edf4e855a25e9c1"}, - {file = "aiohttp-3.11.13-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:85fa0b18558eb1427090912bd456a01f71edab0872f4e0f9e4285571941e4090"}, - {file = "aiohttp-3.11.13-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a86dc177eb4c286c19d1823ac296299f59ed8106c9536d2b559f65836e0fb2c6"}, - {file = "aiohttp-3.11.13-cp39-cp39-win32.whl", hash = "sha256:684eea71ab6e8ade86b9021bb62af4bf0881f6be4e926b6b5455de74e420783a"}, - {file = "aiohttp-3.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:82c249f2bfa5ecbe4a1a7902c81c0fba52ed9ebd0176ab3047395d02ad96cfcb"}, - {file = "aiohttp-3.11.13.tar.gz", hash = "sha256:8ce789231404ca8fff7f693cdce398abf6d90fd5dae2b1847477196c243b1fbb"}, + {file = "aiohttp-3.11.16-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb46bb0f24813e6cede6cc07b1961d4b04f331f7112a23b5e21f567da4ee50aa"}, + {file = "aiohttp-3.11.16-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:54eb3aead72a5c19fad07219acd882c1643a1027fbcdefac9b502c267242f955"}, + {file = "aiohttp-3.11.16-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:38bea84ee4fe24ebcc8edeb7b54bf20f06fd53ce4d2cc8b74344c5b9620597fd"}, + {file = "aiohttp-3.11.16-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0666afbe984f6933fe72cd1f1c3560d8c55880a0bdd728ad774006eb4241ecd"}, + {file = "aiohttp-3.11.16-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ba92a2d9ace559a0a14b03d87f47e021e4fa7681dc6970ebbc7b447c7d4b7cd"}, + {file = "aiohttp-3.11.16-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ad1d59fd7114e6a08c4814983bb498f391c699f3c78712770077518cae63ff7"}, + {file = "aiohttp-3.11.16-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b88a2bf26965f2015a771381624dd4b0839034b70d406dc74fd8be4cc053e3"}, + {file = "aiohttp-3.11.16-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:576f5ca28d1b3276026f7df3ec841ae460e0fc3aac2a47cbf72eabcfc0f102e1"}, + {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a2a450bcce4931b295fc0848f384834c3f9b00edfc2150baafb4488c27953de6"}, + {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:37dcee4906454ae377be5937ab2a66a9a88377b11dd7c072df7a7c142b63c37c"}, + {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4d0c970c0d602b1017e2067ff3b7dac41c98fef4f7472ec2ea26fd8a4e8c2149"}, + {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:004511d3413737700835e949433536a2fe95a7d0297edd911a1e9705c5b5ea43"}, + {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:c15b2271c44da77ee9d822552201180779e5e942f3a71fb74e026bf6172ff287"}, + {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ad9509ffb2396483ceacb1eee9134724443ee45b92141105a4645857244aecc8"}, + {file = "aiohttp-3.11.16-cp310-cp310-win32.whl", hash = "sha256:634d96869be6c4dc232fc503e03e40c42d32cfaa51712aee181e922e61d74814"}, + {file = "aiohttp-3.11.16-cp310-cp310-win_amd64.whl", hash = "sha256:938f756c2b9374bbcc262a37eea521d8a0e6458162f2a9c26329cc87fdf06534"}, + {file = "aiohttp-3.11.16-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8cb0688a8d81c63d716e867d59a9ccc389e97ac7037ebef904c2b89334407180"}, + {file = "aiohttp-3.11.16-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ad1fb47da60ae1ddfb316f0ff16d1f3b8e844d1a1e154641928ea0583d486ed"}, + {file = "aiohttp-3.11.16-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:df7db76400bf46ec6a0a73192b14c8295bdb9812053f4fe53f4e789f3ea66bbb"}, + {file = "aiohttp-3.11.16-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc3a145479a76ad0ed646434d09216d33d08eef0d8c9a11f5ae5cdc37caa3540"}, + {file = "aiohttp-3.11.16-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d007aa39a52d62373bd23428ba4a2546eed0e7643d7bf2e41ddcefd54519842c"}, + {file = "aiohttp-3.11.16-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6ddd90d9fb4b501c97a4458f1c1720e42432c26cb76d28177c5b5ad4e332601"}, + {file = "aiohttp-3.11.16-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a2f451849e6b39e5c226803dcacfa9c7133e9825dcefd2f4e837a2ec5a3bb98"}, + {file = "aiohttp-3.11.16-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8df6612df74409080575dca38a5237282865408016e65636a76a2eb9348c2567"}, + {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:78e6e23b954644737e385befa0deb20233e2dfddf95dd11e9db752bdd2a294d3"}, + {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:696ef00e8a1f0cec5e30640e64eca75d8e777933d1438f4facc9c0cdf288a810"}, + {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3538bc9fe1b902bef51372462e3d7c96fce2b566642512138a480b7adc9d508"}, + {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3ab3367bb7f61ad18793fea2ef71f2d181c528c87948638366bf1de26e239183"}, + {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:56a3443aca82abda0e07be2e1ecb76a050714faf2be84256dae291182ba59049"}, + {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:61c721764e41af907c9d16b6daa05a458f066015abd35923051be8705108ed17"}, + {file = "aiohttp-3.11.16-cp311-cp311-win32.whl", hash = "sha256:3e061b09f6fa42997cf627307f220315e313ece74907d35776ec4373ed718b86"}, + {file = "aiohttp-3.11.16-cp311-cp311-win_amd64.whl", hash = "sha256:745f1ed5e2c687baefc3c5e7b4304e91bf3e2f32834d07baaee243e349624b24"}, + {file = "aiohttp-3.11.16-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:911a6e91d08bb2c72938bc17f0a2d97864c531536b7832abee6429d5296e5b27"}, + {file = "aiohttp-3.11.16-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac13b71761e49d5f9e4d05d33683bbafef753e876e8e5a7ef26e937dd766713"}, + {file = "aiohttp-3.11.16-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fd36c119c5d6551bce374fcb5c19269638f8d09862445f85a5a48596fd59f4bb"}, + {file = "aiohttp-3.11.16-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d489d9778522fbd0f8d6a5c6e48e3514f11be81cb0a5954bdda06f7e1594b321"}, + {file = "aiohttp-3.11.16-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69a2cbd61788d26f8f1e626e188044834f37f6ae3f937bd9f08b65fc9d7e514e"}, + {file = "aiohttp-3.11.16-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd464ba806e27ee24a91362ba3621bfc39dbbb8b79f2e1340201615197370f7c"}, + {file = "aiohttp-3.11.16-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce63ae04719513dd2651202352a2beb9f67f55cb8490c40f056cea3c5c355ce"}, + {file = "aiohttp-3.11.16-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09b00dd520d88eac9d1768439a59ab3d145065c91a8fab97f900d1b5f802895e"}, + {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7f6428fee52d2bcf96a8aa7b62095b190ee341ab0e6b1bcf50c615d7966fd45b"}, + {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:13ceac2c5cdcc3f64b9015710221ddf81c900c5febc505dbd8f810e770011540"}, + {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fadbb8f1d4140825069db3fedbbb843290fd5f5bc0a5dbd7eaf81d91bf1b003b"}, + {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6a792ce34b999fbe04a7a71a90c74f10c57ae4c51f65461a411faa70e154154e"}, + {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f4065145bf69de124accdd17ea5f4dc770da0a6a6e440c53f6e0a8c27b3e635c"}, + {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa73e8c2656a3653ae6c307b3f4e878a21f87859a9afab228280ddccd7369d71"}, + {file = "aiohttp-3.11.16-cp312-cp312-win32.whl", hash = "sha256:f244b8e541f414664889e2c87cac11a07b918cb4b540c36f7ada7bfa76571ea2"}, + {file = "aiohttp-3.11.16-cp312-cp312-win_amd64.whl", hash = "sha256:23a15727fbfccab973343b6d1b7181bfb0b4aa7ae280f36fd2f90f5476805682"}, + {file = "aiohttp-3.11.16-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a3814760a1a700f3cfd2f977249f1032301d0a12c92aba74605cfa6ce9f78489"}, + {file = "aiohttp-3.11.16-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9b751a6306f330801665ae69270a8a3993654a85569b3469662efaad6cf5cc50"}, + {file = "aiohttp-3.11.16-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ad497f38a0d6c329cb621774788583ee12321863cd4bd9feee1effd60f2ad133"}, + {file = "aiohttp-3.11.16-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca37057625693d097543bd88076ceebeb248291df9d6ca8481349efc0b05dcd0"}, + {file = "aiohttp-3.11.16-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5abcbba9f4b463a45c8ca8b7720891200658f6f46894f79517e6cd11f3405ca"}, + {file = "aiohttp-3.11.16-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f420bfe862fb357a6d76f2065447ef6f484bc489292ac91e29bc65d2d7a2c84d"}, + {file = "aiohttp-3.11.16-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58ede86453a6cf2d6ce40ef0ca15481677a66950e73b0a788917916f7e35a0bb"}, + {file = "aiohttp-3.11.16-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fdec0213244c39973674ca2a7f5435bf74369e7d4e104d6c7473c81c9bcc8c4"}, + {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:72b1b03fb4655c1960403c131740755ec19c5898c82abd3961c364c2afd59fe7"}, + {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:780df0d837276276226a1ff803f8d0fa5f8996c479aeef52eb040179f3156cbd"}, + {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ecdb8173e6c7aa09eee342ac62e193e6904923bd232e76b4157ac0bfa670609f"}, + {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a6db7458ab89c7d80bc1f4e930cc9df6edee2200127cfa6f6e080cf619eddfbd"}, + {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2540ddc83cc724b13d1838026f6a5ad178510953302a49e6d647f6e1de82bc34"}, + {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3b4e6db8dc4879015b9955778cfb9881897339c8fab7b3676f8433f849425913"}, + {file = "aiohttp-3.11.16-cp313-cp313-win32.whl", hash = "sha256:493910ceb2764f792db4dc6e8e4b375dae1b08f72e18e8f10f18b34ca17d0979"}, + {file = "aiohttp-3.11.16-cp313-cp313-win_amd64.whl", hash = "sha256:42864e70a248f5f6a49fdaf417d9bc62d6e4d8ee9695b24c5916cb4bb666c802"}, + {file = "aiohttp-3.11.16-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bbcba75fe879ad6fd2e0d6a8d937f34a571f116a0e4db37df8079e738ea95c71"}, + {file = "aiohttp-3.11.16-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:87a6e922b2b2401e0b0cf6b976b97f11ec7f136bfed445e16384fbf6fd5e8602"}, + {file = "aiohttp-3.11.16-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccf10f16ab498d20e28bc2b5c1306e9c1512f2840f7b6a67000a517a4b37d5ee"}, + {file = "aiohttp-3.11.16-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb3d0cc5cdb926090748ea60172fa8a213cec728bd6c54eae18b96040fcd6227"}, + {file = "aiohttp-3.11.16-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d07502cc14ecd64f52b2a74ebbc106893d9a9717120057ea9ea1fd6568a747e7"}, + {file = "aiohttp-3.11.16-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:776c8e959a01e5e8321f1dec77964cb6101020a69d5a94cd3d34db6d555e01f7"}, + {file = "aiohttp-3.11.16-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0902e887b0e1d50424112f200eb9ae3dfed6c0d0a19fc60f633ae5a57c809656"}, + {file = "aiohttp-3.11.16-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e87fd812899aa78252866ae03a048e77bd11b80fb4878ce27c23cade239b42b2"}, + {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0a950c2eb8ff17361abd8c85987fd6076d9f47d040ebffce67dce4993285e973"}, + {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:c10d85e81d0b9ef87970ecbdbfaeec14a361a7fa947118817fcea8e45335fa46"}, + {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:7951decace76a9271a1ef181b04aa77d3cc309a02a51d73826039003210bdc86"}, + {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:14461157d8426bcb40bd94deb0450a6fa16f05129f7da546090cebf8f3123b0f"}, + {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9756d9b9d4547e091f99d554fbba0d2a920aab98caa82a8fb3d3d9bee3c9ae85"}, + {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:87944bd16b7fe6160607f6a17808abd25f17f61ae1e26c47a491b970fb66d8cb"}, + {file = "aiohttp-3.11.16-cp39-cp39-win32.whl", hash = "sha256:92b7ee222e2b903e0a4b329a9943d432b3767f2d5029dbe4ca59fb75223bbe2e"}, + {file = "aiohttp-3.11.16-cp39-cp39-win_amd64.whl", hash = "sha256:17ae4664031aadfbcb34fd40ffd90976671fa0c0286e6c4113989f78bebab37a"}, + {file = "aiohttp-3.11.16.tar.gz", hash = "sha256:16f8a2c9538c14a557b4d309ed4d0a7c60f0253e8ed7b6c9a2859a7582f8b1b8"}, ] [package.dependencies] @@ -135,14 +135,14 @@ webargs = ">=8.4.0" [[package]] name = "aiohttp-cors" -version = "0.8.0" +version = "0.8.1" description = "CORS support for aiohttp" optional = false -python-versions = "*" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohttp_cors-0.8.0-py3-none-any.whl", hash = "sha256:b656eeadb84c8fc6771b07460419b100f20dee1d6bf403505b5bd347894c7941"}, - {file = "aiohttp_cors-0.8.0.tar.gz", hash = "sha256:ec70f38432c938e39d240ff38a7d789a5aa0a18087882c12d6cc141eef1144f6"}, + {file = "aiohttp_cors-0.8.1-py3-none-any.whl", hash = "sha256:3180cf304c5c712d626b9162b195b1db7ddf976a2a25172b35bb2448b890a80d"}, + {file = "aiohttp_cors-0.8.1.tar.gz", hash = "sha256:ccacf9cb84b64939ea15f859a146af1f662a6b1d68175754a07315e305fb1403"}, ] [package.dependencies] @@ -213,16 +213,16 @@ yaml = ["PyYAML (>=3.10)"] [[package]] name = "aries-askar" -version = "0.4.3" +version = "0.4.4" description = "" optional = false python-versions = ">=3.6.3" groups = ["main"] files = [ - {file = "aries_askar-0.4.3-py3-none-macosx_10_9_universal2.whl", hash = "sha256:fd4073f4abc7bfe423f3a637cb0d2e5fb1b96cfd0e798ee69e26eb5b9528c3e4"}, - {file = "aries_askar-0.4.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:a787fdbf343efcdb9f26ce75ed934c2d48378cef08ae5ce69e997cba7c3f1992"}, - {file = "aries_askar-0.4.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e21025d841c861c20dbae6201863cb1fe76b395c2eec231835bf8703356bb157"}, - {file = "aries_askar-0.4.3-py3-none-win_amd64.whl", hash = "sha256:ea25cc6bed206a8df9c55b09ebead18edcb669740d1868d884ba88699dc95f67"}, + {file = "aries_askar-0.4.4-py3-none-macosx_10_9_universal2.whl", hash = "sha256:465e7cd34e6f22555d5a147f6f540524dba33d4c701da00847399a45debe079f"}, + {file = "aries_askar-0.4.4-py3-none-manylinux2014_aarch64.whl", hash = "sha256:982aec8a865f3600cb73c657c9fec2515464b812e7e8fe91d2a9d179c6f9bd5e"}, + {file = "aries_askar-0.4.4-py3-none-manylinux2014_x86_64.whl", hash = "sha256:bf5793abdfa2cc417c64b4713ba5635a4e5a1c248699cbe405cf218d814c84d4"}, + {file = "aries_askar-0.4.4-py3-none-win_amd64.whl", hash = "sha256:51f8b4f5e4c8fddef96b7b729ec430dcdcf31cc74e4183ea08fe70191d49246e"}, ] [[package]] @@ -540,75 +540,75 @@ yaml = ["PyYAML"] [[package]] name = "coverage" -version = "7.6.12" +version = "7.8.0" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "coverage-7.6.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8"}, - {file = "coverage-7.6.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879"}, - {file = "coverage-7.6.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06097c7abfa611c91edb9e6920264e5be1d6ceb374efb4986f38b09eed4cb2fe"}, - {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:220fa6c0ad7d9caef57f2c8771918324563ef0d8272c94974717c3909664e674"}, - {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3688b99604a24492bcfe1c106278c45586eb819bf66a654d8a9a1433022fb2eb"}, - {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1a987778b9c71da2fc8948e6f2656da6ef68f59298b7e9786849634c35d2c3c"}, - {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cec6b9ce3bd2b7853d4a4563801292bfee40b030c05a3d29555fd2a8ee9bd68c"}, - {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ace9048de91293e467b44bce0f0381345078389814ff6e18dbac8fdbf896360e"}, - {file = "coverage-7.6.12-cp310-cp310-win32.whl", hash = "sha256:ea31689f05043d520113e0552f039603c4dd71fa4c287b64cb3606140c66f425"}, - {file = "coverage-7.6.12-cp310-cp310-win_amd64.whl", hash = "sha256:676f92141e3c5492d2a1596d52287d0d963df21bf5e55c8b03075a60e1ddf8aa"}, - {file = "coverage-7.6.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015"}, - {file = "coverage-7.6.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45"}, - {file = "coverage-7.6.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702"}, - {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0"}, - {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f"}, - {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f"}, - {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d"}, - {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba"}, - {file = "coverage-7.6.12-cp311-cp311-win32.whl", hash = "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f"}, - {file = "coverage-7.6.12-cp311-cp311-win_amd64.whl", hash = "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558"}, - {file = "coverage-7.6.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad"}, - {file = "coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3"}, - {file = "coverage-7.6.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574"}, - {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985"}, - {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750"}, - {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea"}, - {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3"}, - {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a"}, - {file = "coverage-7.6.12-cp312-cp312-win32.whl", hash = "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95"}, - {file = "coverage-7.6.12-cp312-cp312-win_amd64.whl", hash = "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288"}, - {file = "coverage-7.6.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:488c27b3db0ebee97a830e6b5a3ea930c4a6e2c07f27a5e67e1b3532e76b9ef1"}, - {file = "coverage-7.6.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d1095bbee1851269f79fd8e0c9b5544e4c00c0c24965e66d8cba2eb5bb535fd"}, - {file = "coverage-7.6.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0533adc29adf6a69c1baa88c3d7dbcaadcffa21afbed3ca7a225a440e4744bf9"}, - {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53c56358d470fa507a2b6e67a68fd002364d23c83741dbc4c2e0680d80ca227e"}, - {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cbb1a3027c79ca6310bf101014614f6e6e18c226474606cf725238cf5bc2d4"}, - {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79cac3390bfa9836bb795be377395f28410811c9066bc4eefd8015258a7578c6"}, - {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b148068e881faa26d878ff63e79650e208e95cf1c22bd3f77c3ca7b1d9821a3"}, - {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8bec2ac5da793c2685ce5319ca9bcf4eee683b8a1679051f8e6ec04c4f2fd7dc"}, - {file = "coverage-7.6.12-cp313-cp313-win32.whl", hash = "sha256:200e10beb6ddd7c3ded322a4186313d5ca9e63e33d8fab4faa67ef46d3460af3"}, - {file = "coverage-7.6.12-cp313-cp313-win_amd64.whl", hash = "sha256:2b996819ced9f7dbb812c701485d58f261bef08f9b85304d41219b1496b591ef"}, - {file = "coverage-7.6.12-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:299cf973a7abff87a30609879c10df0b3bfc33d021e1adabc29138a48888841e"}, - {file = "coverage-7.6.12-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b467a8c56974bf06e543e69ad803c6865249d7a5ccf6980457ed2bc50312703"}, - {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2458f275944db8129f95d91aee32c828a408481ecde3b30af31d552c2ce284a0"}, - {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a9d8be07fb0832636a0f72b80d2a652fe665e80e720301fb22b191c3434d924"}, - {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d47376a4f445e9743f6c83291e60adb1b127607a3618e3185bbc8091f0467b"}, - {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b95574d06aa9d2bd6e5cc35a5bbe35696342c96760b69dc4287dbd5abd4ad51d"}, - {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ecea0c38c9079570163d663c0433a9af4094a60aafdca491c6a3d248c7432827"}, - {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2251fabcfee0a55a8578a9d29cecfee5f2de02f11530e7d5c5a05859aa85aee9"}, - {file = "coverage-7.6.12-cp313-cp313t-win32.whl", hash = "sha256:eb5507795caabd9b2ae3f1adc95f67b1104971c22c624bb354232d65c4fc90b3"}, - {file = "coverage-7.6.12-cp313-cp313t-win_amd64.whl", hash = "sha256:f60a297c3987c6c02ffb29effc70eadcbb412fe76947d394a1091a3615948e2f"}, - {file = "coverage-7.6.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e7575ab65ca8399c8c4f9a7d61bbd2d204c8b8e447aab9d355682205c9dd948d"}, - {file = "coverage-7.6.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8161d9fbc7e9fe2326de89cd0abb9f3599bccc1287db0aba285cb68d204ce929"}, - {file = "coverage-7.6.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a1e465f398c713f1b212400b4e79a09829cd42aebd360362cd89c5bdc44eb87"}, - {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f25d8b92a4e31ff1bd873654ec367ae811b3a943583e05432ea29264782dc32c"}, - {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a936309a65cc5ca80fa9f20a442ff9e2d06927ec9a4f54bcba9c14c066323f2"}, - {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aa6f302a3a0b5f240ee201297fff0bbfe2fa0d415a94aeb257d8b461032389bd"}, - {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f973643ef532d4f9be71dd88cf7588936685fdb576d93a79fe9f65bc337d9d73"}, - {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:78f5243bb6b1060aed6213d5107744c19f9571ec76d54c99cc15938eb69e0e86"}, - {file = "coverage-7.6.12-cp39-cp39-win32.whl", hash = "sha256:69e62c5034291c845fc4df7f8155e8544178b6c774f97a99e2734b05eb5bed31"}, - {file = "coverage-7.6.12-cp39-cp39-win_amd64.whl", hash = "sha256:b01a840ecc25dce235ae4c1b6a0daefb2a203dba0e6e980637ee9c2f6ee0df57"}, - {file = "coverage-7.6.12-pp39.pp310-none-any.whl", hash = "sha256:7e39e845c4d764208e7b8f6a21c541ade741e2c41afabdfa1caa28687a3c98cf"}, - {file = "coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953"}, - {file = "coverage-7.6.12.tar.gz", hash = "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2"}, + {file = "coverage-7.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2931f66991175369859b5fd58529cd4b73582461877ecfd859b6549869287ffe"}, + {file = "coverage-7.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52a523153c568d2c0ef8826f6cc23031dc86cffb8c6aeab92c4ff776e7951b28"}, + {file = "coverage-7.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c8a5c139aae4c35cbd7cadca1df02ea8cf28a911534fc1b0456acb0b14234f3"}, + {file = "coverage-7.8.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a26c0c795c3e0b63ec7da6efded5f0bc856d7c0b24b2ac84b4d1d7bc578d676"}, + {file = "coverage-7.8.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:821f7bcbaa84318287115d54becb1915eece6918136c6f91045bb84e2f88739d"}, + {file = "coverage-7.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a321c61477ff8ee705b8a5fed370b5710c56b3a52d17b983d9215861e37b642a"}, + {file = "coverage-7.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ed2144b8a78f9d94d9515963ed273d620e07846acd5d4b0a642d4849e8d91a0c"}, + {file = "coverage-7.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:042e7841a26498fff7a37d6fda770d17519982f5b7d8bf5278d140b67b61095f"}, + {file = "coverage-7.8.0-cp310-cp310-win32.whl", hash = "sha256:f9983d01d7705b2d1f7a95e10bbe4091fabc03a46881a256c2787637b087003f"}, + {file = "coverage-7.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:5a570cd9bd20b85d1a0d7b009aaf6c110b52b5755c17be6962f8ccd65d1dbd23"}, + {file = "coverage-7.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e7ac22a0bb2c7c49f441f7a6d46c9c80d96e56f5a8bc6972529ed43c8b694e27"}, + {file = "coverage-7.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf13d564d310c156d1c8e53877baf2993fb3073b2fc9f69790ca6a732eb4bfea"}, + {file = "coverage-7.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5761c70c017c1b0d21b0815a920ffb94a670c8d5d409d9b38857874c21f70d7"}, + {file = "coverage-7.8.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ff52d790c7e1628241ffbcaeb33e07d14b007b6eb00a19320c7b8a7024c040"}, + {file = "coverage-7.8.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d39fc4817fd67b3915256af5dda75fd4ee10621a3d484524487e33416c6f3543"}, + {file = "coverage-7.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b44674870709017e4b4036e3d0d6c17f06a0e6d4436422e0ad29b882c40697d2"}, + {file = "coverage-7.8.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8f99eb72bf27cbb167b636eb1726f590c00e1ad375002230607a844d9e9a2318"}, + {file = "coverage-7.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b571bf5341ba8c6bc02e0baeaf3b061ab993bf372d982ae509807e7f112554e9"}, + {file = "coverage-7.8.0-cp311-cp311-win32.whl", hash = "sha256:e75a2ad7b647fd8046d58c3132d7eaf31b12d8a53c0e4b21fa9c4d23d6ee6d3c"}, + {file = "coverage-7.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:3043ba1c88b2139126fc72cb48574b90e2e0546d4c78b5299317f61b7f718b78"}, + {file = "coverage-7.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bbb5cc845a0292e0c520656d19d7ce40e18d0e19b22cb3e0409135a575bf79fc"}, + {file = "coverage-7.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4dfd9a93db9e78666d178d4f08a5408aa3f2474ad4d0e0378ed5f2ef71640cb6"}, + {file = "coverage-7.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f017a61399f13aa6d1039f75cd467be388d157cd81f1a119b9d9a68ba6f2830d"}, + {file = "coverage-7.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0915742f4c82208ebf47a2b154a5334155ed9ef9fe6190674b8a46c2fb89cb05"}, + {file = "coverage-7.8.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a40fcf208e021eb14b0fac6bdb045c0e0cab53105f93ba0d03fd934c956143a"}, + {file = "coverage-7.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a1f406a8e0995d654b2ad87c62caf6befa767885301f3b8f6f73e6f3c31ec3a6"}, + {file = "coverage-7.8.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:77af0f6447a582fdc7de5e06fa3757a3ef87769fbb0fdbdeba78c23049140a47"}, + {file = "coverage-7.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f2d32f95922927186c6dbc8bc60df0d186b6edb828d299ab10898ef3f40052fe"}, + {file = "coverage-7.8.0-cp312-cp312-win32.whl", hash = "sha256:769773614e676f9d8e8a0980dd7740f09a6ea386d0f383db6821df07d0f08545"}, + {file = "coverage-7.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:e5d2b9be5b0693cf21eb4ce0ec8d211efb43966f6657807f6859aab3814f946b"}, + {file = "coverage-7.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ac46d0c2dd5820ce93943a501ac5f6548ea81594777ca585bf002aa8854cacd"}, + {file = "coverage-7.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:771eb7587a0563ca5bb6f622b9ed7f9d07bd08900f7589b4febff05f469bea00"}, + {file = "coverage-7.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42421e04069fb2cbcbca5a696c4050b84a43b05392679d4068acbe65449b5c64"}, + {file = "coverage-7.8.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:554fec1199d93ab30adaa751db68acec2b41c5602ac944bb19187cb9a41a8067"}, + {file = "coverage-7.8.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aaeb00761f985007b38cf463b1d160a14a22c34eb3f6a39d9ad6fc27cb73008"}, + {file = "coverage-7.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:581a40c7b94921fffd6457ffe532259813fc68eb2bdda60fa8cc343414ce3733"}, + {file = "coverage-7.8.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f319bae0321bc838e205bf9e5bc28f0a3165f30c203b610f17ab5552cff90323"}, + {file = "coverage-7.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04bfec25a8ef1c5f41f5e7e5c842f6b615599ca8ba8391ec33a9290d9d2db3a3"}, + {file = "coverage-7.8.0-cp313-cp313-win32.whl", hash = "sha256:dd19608788b50eed889e13a5d71d832edc34fc9dfce606f66e8f9f917eef910d"}, + {file = "coverage-7.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:a9abbccd778d98e9c7e85038e35e91e67f5b520776781d9a1e2ee9d400869487"}, + {file = "coverage-7.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:18c5ae6d061ad5b3e7eef4363fb27a0576012a7447af48be6c75b88494c6cf25"}, + {file = "coverage-7.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:95aa6ae391a22bbbce1b77ddac846c98c5473de0372ba5c463480043a07bff42"}, + {file = "coverage-7.8.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e013b07ba1c748dacc2a80e69a46286ff145935f260eb8c72df7185bf048f502"}, + {file = "coverage-7.8.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d766a4f0e5aa1ba056ec3496243150698dc0481902e2b8559314368717be82b1"}, + {file = "coverage-7.8.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad80e6b4a0c3cb6f10f29ae4c60e991f424e6b14219d46f1e7d442b938ee68a4"}, + {file = "coverage-7.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b87eb6fc9e1bb8f98892a2458781348fa37e6925f35bb6ceb9d4afd54ba36c73"}, + {file = "coverage-7.8.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d1ba00ae33be84066cfbe7361d4e04dec78445b2b88bdb734d0d1cbab916025a"}, + {file = "coverage-7.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f3c38e4e5ccbdc9198aecc766cedbb134b2d89bf64533973678dfcf07effd883"}, + {file = "coverage-7.8.0-cp313-cp313t-win32.whl", hash = "sha256:379fe315e206b14e21db5240f89dc0774bdd3e25c3c58c2c733c99eca96f1ada"}, + {file = "coverage-7.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2e4b6b87bb0c846a9315e3ab4be2d52fac905100565f4b92f02c445c8799e257"}, + {file = "coverage-7.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa260de59dfb143af06dcf30c2be0b200bed2a73737a8a59248fcb9fa601ef0f"}, + {file = "coverage-7.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:96121edfa4c2dfdda409877ea8608dd01de816a4dc4a0523356067b305e4e17a"}, + {file = "coverage-7.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8af63b9afa1031c0ef05b217faa598f3069148eeee6bb24b79da9012423b82"}, + {file = "coverage-7.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89b1f4af0d4afe495cd4787a68e00f30f1d15939f550e869de90a86efa7e0814"}, + {file = "coverage-7.8.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94ec0be97723ae72d63d3aa41961a0b9a6f5a53ff599813c324548d18e3b9e8c"}, + {file = "coverage-7.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8a1d96e780bdb2d0cbb297325711701f7c0b6f89199a57f2049e90064c29f6bd"}, + {file = "coverage-7.8.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f1d8a2a57b47142b10374902777e798784abf400a004b14f1b0b9eaf1e528ba4"}, + {file = "coverage-7.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cf60dd2696b457b710dd40bf17ad269d5f5457b96442f7f85722bdb16fa6c899"}, + {file = "coverage-7.8.0-cp39-cp39-win32.whl", hash = "sha256:be945402e03de47ba1872cd5236395e0f4ad635526185a930735f66710e1bd3f"}, + {file = "coverage-7.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:90e7fbc6216ecaffa5a880cdc9c77b7418c1dcb166166b78dbc630d07f278cc3"}, + {file = "coverage-7.8.0-pp39.pp310.pp311-none-any.whl", hash = "sha256:b8194fb8e50d556d5849753de991d390c5a1edeeba50f68e3a9253fbd8bf8ccd"}, + {file = "coverage-7.8.0-py3-none-any.whl", hash = "sha256:dbf364b4c5e7bae9250528167dfe40219b62e2d573c854d74be213e1e52069f7"}, + {file = "coverage-7.8.0.tar.gz", hash = "sha256:7a3d62b3b03b4b6fd41a085f3574874cf946cb4604d2b4d3e8dca8cd570ca501"}, ] [package.extras] @@ -1260,14 +1260,14 @@ files = [ [[package]] name = "iniconfig" -version = "2.0.0" +version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, + {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, ] [[package]] @@ -1309,8 +1309,6 @@ python-versions = "*" groups = ["main"] files = [ {file = "jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c"}, - {file = "jsonpath_ng-1.7.0-py2-none-any.whl", hash = "sha256:898c93fc173f0c336784a3fa63d7434297544b7198124a68f9a3ef9597b0ae6e"}, - {file = "jsonpath_ng-1.7.0-py3-none-any.whl", hash = "sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6"}, ] [package.dependencies] @@ -1334,150 +1332,150 @@ typing-extensions = ">=4.5.0" [[package]] name = "lxml" -version = "5.3.1" +version = "5.3.2" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=3.6" groups = ["main"] files = [ - {file = "lxml-5.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a4058f16cee694577f7e4dd410263cd0ef75644b43802a689c2b3c2a7e69453b"}, - {file = "lxml-5.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:364de8f57d6eda0c16dcfb999af902da31396949efa0e583e12675d09709881b"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:528f3a0498a8edc69af0559bdcf8a9f5a8bf7c00051a6ef3141fdcf27017bbf5"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db4743e30d6f5f92b6d2b7c86b3ad250e0bad8dee4b7ad8a0c44bfb276af89a3"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17b5d7f8acf809465086d498d62a981fa6a56d2718135bb0e4aa48c502055f5c"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:928e75a7200a4c09e6efc7482a1337919cc61fe1ba289f297827a5b76d8969c2"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a997b784a639e05b9d4053ef3b20c7e447ea80814a762f25b8ed5a89d261eac"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:7b82e67c5feb682dbb559c3e6b78355f234943053af61606af126df2183b9ef9"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:f1de541a9893cf8a1b1db9bf0bf670a2decab42e3e82233d36a74eda7822b4c9"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:de1fc314c3ad6bc2f6bd5b5a5b9357b8c6896333d27fdbb7049aea8bd5af2d79"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:7c0536bd9178f754b277a3e53f90f9c9454a3bd108b1531ffff720e082d824f2"}, - {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:68018c4c67d7e89951a91fbd371e2e34cd8cfc71f0bb43b5332db38497025d51"}, - {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aa826340a609d0c954ba52fd831f0fba2a4165659ab0ee1a15e4aac21f302406"}, - {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:796520afa499732191e39fc95b56a3b07f95256f2d22b1c26e217fb69a9db5b5"}, - {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3effe081b3135237da6e4c4530ff2a868d3f80be0bda027e118a5971285d42d0"}, - {file = "lxml-5.3.1-cp310-cp310-win32.whl", hash = "sha256:a22f66270bd6d0804b02cd49dae2b33d4341015545d17f8426f2c4e22f557a23"}, - {file = "lxml-5.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:0bcfadea3cdc68e678d2b20cb16a16716887dd00a881e16f7d806c2138b8ff0c"}, - {file = "lxml-5.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e220f7b3e8656ab063d2eb0cd536fafef396829cafe04cb314e734f87649058f"}, - {file = "lxml-5.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f2cfae0688fd01f7056a17367e3b84f37c545fb447d7282cf2c242b16262607"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67d2f8ad9dcc3a9e826bdc7802ed541a44e124c29b7d95a679eeb58c1c14ade8"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db0c742aad702fd5d0c6611a73f9602f20aec2007c102630c06d7633d9c8f09a"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:198bb4b4dd888e8390afa4f170d4fa28467a7eaf857f1952589f16cfbb67af27"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2a3e412ce1849be34b45922bfef03df32d1410a06d1cdeb793a343c2f1fd666"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b8969dbc8d09d9cd2ae06362c3bad27d03f433252601ef658a49bd9f2b22d79"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5be8f5e4044146a69c96077c7e08f0709c13a314aa5315981185c1f00235fe65"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:133f3493253a00db2c870d3740bc458ebb7d937bd0a6a4f9328373e0db305709"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:52d82b0d436edd6a1d22d94a344b9a58abd6c68c357ed44f22d4ba8179b37629"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b6f92e35e2658a5ed51c6634ceb5ddae32053182851d8cad2a5bc102a359b33"}, - {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:203b1d3eaebd34277be06a3eb880050f18a4e4d60861efba4fb946e31071a295"}, - {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:155e1a5693cf4b55af652f5c0f78ef36596c7f680ff3ec6eb4d7d85367259b2c"}, - {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22ec2b3c191f43ed21f9545e9df94c37c6b49a5af0a874008ddc9132d49a2d9c"}, - {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7eda194dd46e40ec745bf76795a7cccb02a6a41f445ad49d3cf66518b0bd9cff"}, - {file = "lxml-5.3.1-cp311-cp311-win32.whl", hash = "sha256:fb7c61d4be18e930f75948705e9718618862e6fc2ed0d7159b2262be73f167a2"}, - {file = "lxml-5.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:c809eef167bf4a57af4b03007004896f5c60bd38dc3852fcd97a26eae3d4c9e6"}, - {file = "lxml-5.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e69add9b6b7b08c60d7ff0152c7c9a6c45b4a71a919be5abde6f98f1ea16421c"}, - {file = "lxml-5.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4e52e1b148867b01c05e21837586ee307a01e793b94072d7c7b91d2c2da02ffe"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4b382e0e636ed54cd278791d93fe2c4f370772743f02bcbe431a160089025c9"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2e49dc23a10a1296b04ca9db200c44d3eb32c8d8ec532e8c1fd24792276522a"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4399b4226c4785575fb20998dc571bc48125dc92c367ce2602d0d70e0c455eb0"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5412500e0dc5481b1ee9cf6b38bb3b473f6e411eb62b83dc9b62699c3b7b79f7"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c93ed3c998ea8472be98fb55aed65b5198740bfceaec07b2eba551e55b7b9ae"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:63d57fc94eb0bbb4735e45517afc21ef262991d8758a8f2f05dd6e4174944519"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:b450d7cabcd49aa7ab46a3c6aa3ac7e1593600a1a0605ba536ec0f1b99a04322"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:4df0ec814b50275ad6a99bc82a38b59f90e10e47714ac9871e1b223895825468"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d184f85ad2bb1f261eac55cddfcf62a70dee89982c978e92b9a74a1bfef2e367"}, - {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b725e70d15906d24615201e650d5b0388b08a5187a55f119f25874d0103f90dd"}, - {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a31fa7536ec1fb7155a0cd3a4e3d956c835ad0a43e3610ca32384d01f079ea1c"}, - {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3c3c8b55c7fc7b7e8877b9366568cc73d68b82da7fe33d8b98527b73857a225f"}, - {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d61ec60945d694df806a9aec88e8f29a27293c6e424f8ff91c80416e3c617645"}, - {file = "lxml-5.3.1-cp312-cp312-win32.whl", hash = "sha256:f4eac0584cdc3285ef2e74eee1513a6001681fd9753b259e8159421ed28a72e5"}, - {file = "lxml-5.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:29bfc8d3d88e56ea0a27e7c4897b642706840247f59f4377d81be8f32aa0cfbf"}, - {file = "lxml-5.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c093c7088b40d8266f57ed71d93112bd64c6724d31f0794c1e52cc4857c28e0e"}, - {file = "lxml-5.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0884e3f22d87c30694e625b1e62e6f30d39782c806287450d9dc2fdf07692fd"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1637fa31ec682cd5760092adfabe86d9b718a75d43e65e211d5931809bc111e7"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a364e8e944d92dcbf33b6b494d4e0fb3499dcc3bd9485beb701aa4b4201fa414"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:779e851fd0e19795ccc8a9bb4d705d6baa0ef475329fe44a13cf1e962f18ff1e"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c4393600915c308e546dc7003d74371744234e8444a28622d76fe19b98fa59d1"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:673b9d8e780f455091200bba8534d5f4f465944cbdd61f31dc832d70e29064a5"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:2e4a570f6a99e96c457f7bec5ad459c9c420ee80b99eb04cbfcfe3fc18ec6423"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:71f31eda4e370f46af42fc9f264fafa1b09f46ba07bdbee98f25689a04b81c20"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:42978a68d3825eaac55399eb37a4d52012a205c0c6262199b8b44fcc6fd686e8"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:8b1942b3e4ed9ed551ed3083a2e6e0772de1e5e3aca872d955e2e86385fb7ff9"}, - {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:85c4f11be9cf08917ac2a5a8b6e1ef63b2f8e3799cec194417e76826e5f1de9c"}, - {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:231cf4d140b22a923b1d0a0a4e0b4f972e5893efcdec188934cc65888fd0227b"}, - {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5865b270b420eda7b68928d70bb517ccbe045e53b1a428129bb44372bf3d7dd5"}, - {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dbf7bebc2275016cddf3c997bf8a0f7044160714c64a9b83975670a04e6d2252"}, - {file = "lxml-5.3.1-cp313-cp313-win32.whl", hash = "sha256:d0751528b97d2b19a388b302be2a0ee05817097bab46ff0ed76feeec24951f78"}, - {file = "lxml-5.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:91fb6a43d72b4f8863d21f347a9163eecbf36e76e2f51068d59cd004c506f332"}, - {file = "lxml-5.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:016b96c58e9a4528219bb563acf1aaaa8bc5452e7651004894a973f03b84ba81"}, - {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82a4bb10b0beef1434fb23a09f001ab5ca87895596b4581fd53f1e5145a8934a"}, - {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d68eeef7b4d08a25e51897dac29bcb62aba830e9ac6c4e3297ee7c6a0cf6439"}, - {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:f12582b8d3b4c6be1d298c49cb7ae64a3a73efaf4c2ab4e37db182e3545815ac"}, - {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2df7ed5edeb6bd5590914cd61df76eb6cce9d590ed04ec7c183cf5509f73530d"}, - {file = "lxml-5.3.1-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:585c4dc429deebc4307187d2b71ebe914843185ae16a4d582ee030e6cfbb4d8a"}, - {file = "lxml-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:06a20d607a86fccab2fc15a77aa445f2bdef7b49ec0520a842c5c5afd8381576"}, - {file = "lxml-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:057e30d0012439bc54ca427a83d458752ccda725c1c161cc283db07bcad43cf9"}, - {file = "lxml-5.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4867361c049761a56bd21de507cab2c2a608c55102311d142ade7dab67b34f32"}, - {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dddf0fb832486cc1ea71d189cb92eb887826e8deebe128884e15020bb6e3f61"}, - {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bcc211542f7af6f2dfb705f5f8b74e865592778e6cafdfd19c792c244ccce19"}, - {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaca5a812f050ab55426c32177091130b1e49329b3f002a32934cd0245571307"}, - {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:236610b77589faf462337b3305a1be91756c8abc5a45ff7ca8f245a71c5dab70"}, - {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:aed57b541b589fa05ac248f4cb1c46cbb432ab82cbd467d1c4f6a2bdc18aecf9"}, - {file = "lxml-5.3.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:75fa3d6946d317ffc7016a6fcc44f42db6d514b7fdb8b4b28cbe058303cb6e53"}, - {file = "lxml-5.3.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:96eef5b9f336f623ffc555ab47a775495e7e8846dde88de5f941e2906453a1ce"}, - {file = "lxml-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:ef45f31aec9be01379fc6c10f1d9c677f032f2bac9383c827d44f620e8a88407"}, - {file = "lxml-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0611da6b07dd3720f492db1b463a4d1175b096b49438761cc9f35f0d9eaaef5"}, - {file = "lxml-5.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b2aca14c235c7a08558fe0a4786a1a05873a01e86b474dfa8f6df49101853a4e"}, - {file = "lxml-5.3.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae82fce1d964f065c32c9517309f0c7be588772352d2f40b1574a214bd6e6098"}, - {file = "lxml-5.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7aae7a3d63b935babfdc6864b31196afd5145878ddd22f5200729006366bc4d5"}, - {file = "lxml-5.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8e0d177b1fe251c3b1b914ab64135475c5273c8cfd2857964b2e3bb0fe196a7"}, - {file = "lxml-5.3.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:6c4dd3bfd0c82400060896717dd261137398edb7e524527438c54a8c34f736bf"}, - {file = "lxml-5.3.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f1208c1c67ec9e151d78aa3435aa9b08a488b53d9cfac9b699f15255a3461ef2"}, - {file = "lxml-5.3.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:c6aacf00d05b38a5069826e50ae72751cb5bc27bdc4d5746203988e429b385bb"}, - {file = "lxml-5.3.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5881aaa4bf3a2d086c5f20371d3a5856199a0d8ac72dd8d0dbd7a2ecfc26ab73"}, - {file = "lxml-5.3.1-cp38-cp38-win32.whl", hash = "sha256:45fbb70ccbc8683f2fb58bea89498a7274af1d9ec7995e9f4af5604e028233fc"}, - {file = "lxml-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:7512b4d0fc5339d5abbb14d1843f70499cab90d0b864f790e73f780f041615d7"}, - {file = "lxml-5.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5885bc586f1edb48e5d68e7a4b4757b5feb2a496b64f462b4d65950f5af3364f"}, - {file = "lxml-5.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1b92fe86e04f680b848fff594a908edfa72b31bfc3499ef7433790c11d4c8cd8"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a091026c3bf7519ab1e64655a3f52a59ad4a4e019a6f830c24d6430695b1cf6a"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ffb141361108e864ab5f1813f66e4e1164181227f9b1f105b042729b6c15125"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3715cdf0dd31b836433af9ee9197af10e3df41d273c19bb249230043667a5dfd"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88b72eb7222d918c967202024812c2bfb4048deeb69ca328363fb8e15254c549"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa59974880ab5ad8ef3afaa26f9bda148c5f39e06b11a8ada4660ecc9fb2feb3"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3bb8149840daf2c3f97cebf00e4ed4a65a0baff888bf2605a8d0135ff5cf764e"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:0d6b2fa86becfa81f0a0271ccb9eb127ad45fb597733a77b92e8a35e53414914"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:136bf638d92848a939fd8f0e06fcf92d9f2e4b57969d94faae27c55f3d85c05b"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:89934f9f791566e54c1d92cdc8f8fd0009447a5ecdb1ec6b810d5f8c4955f6be"}, - {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a8ade0363f776f87f982572c2860cc43c65ace208db49c76df0a21dde4ddd16e"}, - {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:bfbbab9316330cf81656fed435311386610f78b6c93cc5db4bebbce8dd146675"}, - {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:172d65f7c72a35a6879217bcdb4bb11bc88d55fb4879e7569f55616062d387c2"}, - {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e3c623923967f3e5961d272718655946e5322b8d058e094764180cdee7bab1af"}, - {file = "lxml-5.3.1-cp39-cp39-win32.whl", hash = "sha256:ce0930a963ff593e8bb6fda49a503911accc67dee7e5445eec972668e672a0f0"}, - {file = "lxml-5.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:f7b64fcd670bca8800bc10ced36620c6bbb321e7bc1214b9c0c0df269c1dddc2"}, - {file = "lxml-5.3.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:afa578b6524ff85fb365f454cf61683771d0170470c48ad9d170c48075f86725"}, - {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f5e80adf0aafc7b5454f2c1cb0cde920c9b1f2cbd0485f07cc1d0497c35c5d"}, - {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dd0b80ac2d8f13ffc906123a6f20b459cb50a99222d0da492360512f3e50f84"}, - {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:422c179022ecdedbe58b0e242607198580804253da220e9454ffe848daa1cfd2"}, - {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:524ccfded8989a6595dbdda80d779fb977dbc9a7bc458864fc9a0c2fc15dc877"}, - {file = "lxml-5.3.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:48fd46bf7155def2e15287c6f2b133a2f78e2d22cdf55647269977b873c65499"}, - {file = "lxml-5.3.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:05123fad495a429f123307ac6d8fd6f977b71e9a0b6d9aeeb8f80c017cb17131"}, - {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a243132767150a44e6a93cd1dde41010036e1cbc63cc3e9fe1712b277d926ce3"}, - {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c92ea6d9dd84a750b2bae72ff5e8cf5fdd13e58dda79c33e057862c29a8d5b50"}, - {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2f1be45d4c15f237209bbf123a0e05b5d630c8717c42f59f31ea9eae2ad89394"}, - {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:a83d3adea1e0ee36dac34627f78ddd7f093bb9cfc0a8e97f1572a949b695cb98"}, - {file = "lxml-5.3.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:3edbb9c9130bac05d8c3fe150c51c337a471cc7fdb6d2a0a7d3a88e88a829314"}, - {file = "lxml-5.3.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2f23cf50eccb3255b6e913188291af0150d89dab44137a69e14e4dcb7be981f1"}, - {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df7e5edac4778127f2bf452e0721a58a1cfa4d1d9eac63bdd650535eb8543615"}, - {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:094b28ed8a8a072b9e9e2113a81fda668d2053f2ca9f2d202c2c8c7c2d6516b1"}, - {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:514fe78fc4b87e7a7601c92492210b20a1b0c6ab20e71e81307d9c2e377c64de"}, - {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8fffc08de02071c37865a155e5ea5fce0282e1546fd5bde7f6149fcaa32558ac"}, - {file = "lxml-5.3.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4b0d5cdba1b655d5b18042ac9c9ff50bda33568eb80feaaca4fc237b9c4fbfde"}, - {file = "lxml-5.3.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3031e4c16b59424e8d78522c69b062d301d951dc55ad8685736c3335a97fc270"}, - {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb659702a45136c743bc130760c6f137870d4df3a9e14386478b8a0511abcfca"}, - {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a11b16a33656ffc43c92a5343a28dc71eefe460bcc2a4923a96f292692709f6"}, - {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c5ae125276f254b01daa73e2c103363d3e99e3e10505686ac7d9d2442dd4627a"}, - {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c76722b5ed4a31ba103e0dc77ab869222ec36efe1a614e42e9bcea88a36186fe"}, - {file = "lxml-5.3.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:33e06717c00c788ab4e79bc4726ecc50c54b9bfb55355eae21473c145d83c2d2"}, - {file = "lxml-5.3.1.tar.gz", hash = "sha256:106b7b5d2977b339f1e97efe2778e2ab20e99994cbb0ec5e55771ed0795920c8"}, + {file = "lxml-5.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c4b84d6b580a9625dfa47269bf1fd7fbba7ad69e08b16366a46acb005959c395"}, + {file = "lxml-5.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b4c08ecb26e4270a62f81f81899dfff91623d349e433b126931c9c4577169666"}, + {file = "lxml-5.3.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef926e9f11e307b5a7c97b17c5c609a93fb59ffa8337afac8f89e6fe54eb0b37"}, + {file = "lxml-5.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:017ceeabe739100379fe6ed38b033cd244ce2da4e7f6f07903421f57da3a19a2"}, + {file = "lxml-5.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dae97d9435dc90590f119d056d233c33006b2fd235dd990d5564992261ee7ae8"}, + {file = "lxml-5.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:910f39425c6798ce63c93976ae5af5fff6949e2cb446acbd44d6d892103eaea8"}, + {file = "lxml-5.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9780de781a0d62a7c3680d07963db3048b919fc9e3726d9cfd97296a65ffce1"}, + {file = "lxml-5.3.2-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:1a06b0c6ba2e3ca45a009a78a4eb4d6b63831830c0a83dcdc495c13b9ca97d3e"}, + {file = "lxml-5.3.2-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:4c62d0a34d1110769a1bbaf77871a4b711a6f59c4846064ccb78bc9735978644"}, + {file = "lxml-5.3.2-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:8f961a4e82f411b14538fe5efc3e6b953e17f5e809c463f0756a0d0e8039b700"}, + {file = "lxml-5.3.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:3dfc78f5f9251b6b8ad37c47d4d0bfe63ceb073a916e5b50a3bf5fd67a703335"}, + {file = "lxml-5.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10e690bc03214d3537270c88e492b8612d5e41b884f232df2b069b25b09e6711"}, + {file = "lxml-5.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aa837e6ee9534de8d63bc4c1249e83882a7ac22bd24523f83fad68e6ffdf41ae"}, + {file = "lxml-5.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:da4c9223319400b97a2acdfb10926b807e51b69eb7eb80aad4942c0516934858"}, + {file = "lxml-5.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:dc0e9bdb3aa4d1de703a437576007d366b54f52c9897cae1a3716bb44fc1fc85"}, + {file = "lxml-5.3.2-cp310-cp310-win32.whl", hash = "sha256:5f94909a1022c8ea12711db7e08752ca7cf83e5b57a87b59e8a583c5f35016ad"}, + {file = "lxml-5.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:d64ea1686474074b38da13ae218d9fde0d1dc6525266976808f41ac98d9d7980"}, + {file = "lxml-5.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9d61a7d0d208ace43986a92b111e035881c4ed45b1f5b7a270070acae8b0bfb4"}, + {file = "lxml-5.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:856dfd7eda0b75c29ac80a31a6411ca12209183e866c33faf46e77ace3ce8a79"}, + {file = "lxml-5.3.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a01679e4aad0727bedd4c9407d4d65978e920f0200107ceeffd4b019bd48529"}, + {file = "lxml-5.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b6b37b4c3acb8472d191816d4582379f64d81cecbdce1a668601745c963ca5cc"}, + {file = "lxml-5.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3df5a54e7b7c31755383f126d3a84e12a4e0333db4679462ef1165d702517477"}, + {file = "lxml-5.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c09a40f28dcded933dc16217d6a092be0cc49ae25811d3b8e937c8060647c353"}, + {file = "lxml-5.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1ef20f1851ccfbe6c5a04c67ec1ce49da16ba993fdbabdce87a92926e505412"}, + {file = "lxml-5.3.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:f79a63289dbaba964eb29ed3c103b7911f2dce28c36fe87c36a114e6bd21d7ad"}, + {file = "lxml-5.3.2-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:75a72697d95f27ae00e75086aed629f117e816387b74a2f2da6ef382b460b710"}, + {file = "lxml-5.3.2-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:b9b00c9ee1cc3a76f1f16e94a23c344e0b6e5c10bec7f94cf2d820ce303b8c01"}, + {file = "lxml-5.3.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:77cbcab50cbe8c857c6ba5f37f9a3976499c60eada1bf6d38f88311373d7b4bc"}, + {file = "lxml-5.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:29424058f072a24622a0a15357bca63d796954758248a72da6d512f9bd9a4493"}, + {file = "lxml-5.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7d82737a8afe69a7c80ef31d7626075cc7d6e2267f16bf68af2c764b45ed68ab"}, + {file = "lxml-5.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:95473d1d50a5d9fcdb9321fdc0ca6e1edc164dce4c7da13616247d27f3d21e31"}, + {file = "lxml-5.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2162068f6da83613f8b2a32ca105e37a564afd0d7009b0b25834d47693ce3538"}, + {file = "lxml-5.3.2-cp311-cp311-win32.whl", hash = "sha256:f8695752cf5d639b4e981afe6c99e060621362c416058effd5c704bede9cb5d1"}, + {file = "lxml-5.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:d1a94cbb4ee64af3ab386c2d63d6d9e9cf2e256ac0fd30f33ef0a3c88f575174"}, + {file = "lxml-5.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:16b3897691ec0316a1aa3c6585f61c8b7978475587c5b16fc1d2c28d283dc1b0"}, + {file = "lxml-5.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a8d4b34a0eeaf6e73169dcfd653c8d47f25f09d806c010daf074fba2db5e2d3f"}, + {file = "lxml-5.3.2-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9cd7a959396da425022e1e4214895b5cfe7de7035a043bcc2d11303792b67554"}, + {file = "lxml-5.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cac5eaeec3549c5df7f8f97a5a6db6963b91639389cdd735d5a806370847732b"}, + {file = "lxml-5.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29b5f7d77334877c2146e7bb8b94e4df980325fab0a8af4d524e5d43cd6f789d"}, + {file = "lxml-5.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13f3495cfec24e3d63fffd342cc8141355d1d26ee766ad388775f5c8c5ec3932"}, + {file = "lxml-5.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e70ad4c9658beeff99856926fd3ee5fde8b519b92c693f856007177c36eb2e30"}, + {file = "lxml-5.3.2-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:507085365783abd7879fa0a6fa55eddf4bdd06591b17a2418403bb3aff8a267d"}, + {file = "lxml-5.3.2-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:5bb304f67cbf5dfa07edad904732782cbf693286b9cd85af27059c5779131050"}, + {file = "lxml-5.3.2-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:3d84f5c093645c21c29a4e972b84cb7cf682f707f8706484a5a0c7ff13d7a988"}, + {file = "lxml-5.3.2-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:bdc13911db524bd63f37b0103af014b7161427ada41f1b0b3c9b5b5a9c1ca927"}, + {file = "lxml-5.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ec944539543f66ebc060ae180d47e86aca0188bda9cbfadff47d86b0dc057dc"}, + {file = "lxml-5.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:59d437cc8a7f838282df5a199cf26f97ef08f1c0fbec6e84bd6f5cc2b7913f6e"}, + {file = "lxml-5.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e275961adbd32e15672e14e0cc976a982075208224ce06d149c92cb43db5b93"}, + {file = "lxml-5.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:038aeb6937aa404480c2966b7f26f1440a14005cb0702078c173c028eca72c31"}, + {file = "lxml-5.3.2-cp312-cp312-win32.whl", hash = "sha256:3c2c8d0fa3277147bff180e3590be67597e17d365ce94beb2efa3138a2131f71"}, + {file = "lxml-5.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:77809fcd97dfda3f399102db1794f7280737b69830cd5c961ac87b3c5c05662d"}, + {file = "lxml-5.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:77626571fb5270ceb36134765f25b665b896243529eefe840974269b083e090d"}, + {file = "lxml-5.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:78a533375dc7aa16d0da44af3cf6e96035e484c8c6b2b2445541a5d4d3d289ee"}, + {file = "lxml-5.3.2-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6f62b2404b3f3f0744bbcabb0381c5fe186fa2a9a67ecca3603480f4846c585"}, + {file = "lxml-5.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ea918da00091194526d40c30c4996971f09dacab032607581f8d8872db34fbf"}, + {file = "lxml-5.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c35326f94702a7264aa0eea826a79547d3396a41ae87a70511b9f6e9667ad31c"}, + {file = "lxml-5.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3bef90af21d31c4544bc917f51e04f94ae11b43156356aff243cdd84802cbf2"}, + {file = "lxml-5.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52fa7ba11a495b7cbce51573c73f638f1dcff7b3ee23697467dc063f75352a69"}, + {file = "lxml-5.3.2-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:ad131e2c4d2c3803e736bb69063382334e03648de2a6b8f56a878d700d4b557d"}, + {file = "lxml-5.3.2-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:00a4463ca409ceacd20490a893a7e08deec7870840eff33dc3093067b559ce3e"}, + {file = "lxml-5.3.2-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:87e8d78205331cace2b73ac8249294c24ae3cba98220687b5b8ec5971a2267f1"}, + {file = "lxml-5.3.2-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:bf6389133bb255e530a4f2f553f41c4dd795b1fbb6f797aea1eff308f1e11606"}, + {file = "lxml-5.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b3709fc752b42fb6b6ffa2ba0a5b9871646d97d011d8f08f4d5b3ee61c7f3b2b"}, + {file = "lxml-5.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:abc795703d0de5d83943a4badd770fbe3d1ca16ee4ff3783d7caffc252f309ae"}, + {file = "lxml-5.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:98050830bb6510159f65d9ad1b8aca27f07c01bb3884ba95f17319ccedc4bcf9"}, + {file = "lxml-5.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6ba465a91acc419c5682f8b06bcc84a424a7aa5c91c220241c6fd31de2a72bc6"}, + {file = "lxml-5.3.2-cp313-cp313-win32.whl", hash = "sha256:56a1d56d60ea1ec940f949d7a309e0bff05243f9bd337f585721605670abb1c1"}, + {file = "lxml-5.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:1a580dc232c33d2ad87d02c8a3069d47abbcdce974b9c9cc82a79ff603065dbe"}, + {file = "lxml-5.3.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1a59f7fe888d0ec1916d0ad69364c5400cfa2f885ae0576d909f342e94d26bc9"}, + {file = "lxml-5.3.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d67b50abc2df68502a26ed2ccea60c1a7054c289fb7fc31c12e5e55e4eec66bd"}, + {file = "lxml-5.3.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2cb08d2cb047c98d6fbbb2e77d6edd132ad6e3fa5aa826ffa9ea0c9b1bc74a84"}, + {file = "lxml-5.3.2-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:495ddb7e10911fb4d673d8aa8edd98d1eadafb3b56e8c1b5f427fd33cadc455b"}, + {file = "lxml-5.3.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:884d9308ac7d581b705a3371185282e1b8eebefd68ccf288e00a2d47f077cc51"}, + {file = "lxml-5.3.2-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:37f3d7cf7f2dd2520df6cc8a13df4c3e3f913c8e0a1f9a875e44f9e5f98d7fee"}, + {file = "lxml-5.3.2-cp36-cp36m-win32.whl", hash = "sha256:e885a1bf98a76dff0a0648850c3083b99d9358ef91ba8fa307c681e8e0732503"}, + {file = "lxml-5.3.2-cp36-cp36m-win_amd64.whl", hash = "sha256:b45f505d0d85f4cdd440cd7500689b8e95110371eaa09da0c0b1103e9a05030f"}, + {file = "lxml-5.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b53cd668facd60b4f0dfcf092e01bbfefd88271b5b4e7b08eca3184dd006cb30"}, + {file = "lxml-5.3.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5dea998c891f082fe204dec6565dbc2f9304478f2fc97bd4d7a940fec16c873"}, + {file = "lxml-5.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d46bc3e58b01e4f38d75e0d7f745a46875b7a282df145aca9d1479c65ff11561"}, + {file = "lxml-5.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:661feadde89159fd5f7d7639a81ccae36eec46974c4a4d5ccce533e2488949c8"}, + {file = "lxml-5.3.2-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:43af2a69af2cacc2039024da08a90174e85f3af53483e6b2e3485ced1bf37151"}, + {file = "lxml-5.3.2-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:1539f962d82436f3d386eb9f29b2a29bb42b80199c74a695dff51b367a61ec0a"}, + {file = "lxml-5.3.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:6673920bf976421b5fac4f29b937702eef4555ee42329546a5fc68bae6178a48"}, + {file = "lxml-5.3.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:9fa722a9cd8845594593cce399a49aa6bfc13b6c83a7ee05e2ab346d9253d52f"}, + {file = "lxml-5.3.2-cp37-cp37m-win32.whl", hash = "sha256:2eadd4efa487f4710755415aed3d6ae9ac8b4327ea45226ffccb239766c8c610"}, + {file = "lxml-5.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:83d8707b1b08cd02c04d3056230ec3b771b18c566ec35e723e60cdf037064e08"}, + {file = "lxml-5.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc6e8678bfa5ccba370103976ccfcf776c85c83da9220ead41ea6fd15d2277b4"}, + {file = "lxml-5.3.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0bed509662f67f719119ad56006cd4a38efa68cfa74383060612044915e5f7ad"}, + {file = "lxml-5.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e3925975fadd6fd72a6d80541a6ec75dfbad54044a03aa37282dafcb80fbdfa"}, + {file = "lxml-5.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83c0462dedc5213ac586164c6d7227da9d4d578cf45dd7fbab2ac49b63a008eb"}, + {file = "lxml-5.3.2-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:53e3f9ca72858834688afa17278649d62aa768a4b2018344be00c399c4d29e95"}, + {file = "lxml-5.3.2-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:32ba634ef3f1b20f781019a91d78599224dc45745dd572f951adbf1c0c9b0d75"}, + {file = "lxml-5.3.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:1b16504c53f41da5fcf04868a80ac40a39d3eec5329caf761114caec6e844ad1"}, + {file = "lxml-5.3.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:1f9682786138549da44ca4c49b20e7144d063b75f2b2ba611f4cff9b83db1062"}, + {file = "lxml-5.3.2-cp38-cp38-win32.whl", hash = "sha256:d8f74ef8aacdf6ee5c07566a597634bb8535f6b53dc89790db43412498cf6026"}, + {file = "lxml-5.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:49f1cee0fa27e1ee02589c696a9bdf4027e7427f184fa98e6bef0c6613f6f0fa"}, + {file = "lxml-5.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:741c126bcf9aa939e950e64e5e0a89c8e01eda7a5f5ffdfc67073f2ed849caea"}, + {file = "lxml-5.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ab6e9e6aca1fd7d725ffa132286e70dee5b9a4561c5ed291e836440b82888f89"}, + {file = "lxml-5.3.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58e8c9b9ed3c15c2d96943c14efc324b69be6352fe5585733a7db2bf94d97841"}, + {file = "lxml-5.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7811828ddfb8c23f4f1fbf35e7a7b2edec2f2e4c793dee7c52014f28c4b35238"}, + {file = "lxml-5.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:72968623efb1e12e950cbdcd1d0f28eb14c8535bf4be153f1bfffa818b1cf189"}, + {file = "lxml-5.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ebfceaa2ea588b54efb6160e3520983663d45aed8a3895bb2031ada080fb5f04"}, + {file = "lxml-5.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d685d458505b2bfd2e28c812749fe9194a2b0ce285a83537e4309a187ffa270b"}, + {file = "lxml-5.3.2-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:334e0e414dab1f5366ead8ca34ec3148415f236d5660e175f1d640b11d645847"}, + {file = "lxml-5.3.2-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:02e56f7de72fa82561eae69628a7d6febd7891d72248c7ff7d3e7814d4031017"}, + {file = "lxml-5.3.2-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:638d06b4e1d34d1a074fa87deed5fb55c18485fa0dab97abc5604aad84c12031"}, + {file = "lxml-5.3.2-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:354dab7206d22d7a796fa27c4c5bffddd2393da2ad61835355a4759d435beb47"}, + {file = "lxml-5.3.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d9d9f82ff2c3bf9bb777cb355149f7f3a98ec58f16b7428369dc27ea89556a4c"}, + {file = "lxml-5.3.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:95ad58340e3b7d2b828efc370d1791856613c5cb62ae267158d96e47b3c978c9"}, + {file = "lxml-5.3.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:30fe05f4b7f6e9eb32862745512e7cbd021070ad0f289a7f48d14a0d3fc1d8a9"}, + {file = "lxml-5.3.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:34c688fef86f73dbca0798e0a61bada114677006afa524a8ce97d9e5fabf42e6"}, + {file = "lxml-5.3.2-cp39-cp39-win32.whl", hash = "sha256:4d6d3d1436d57f41984920667ec5ef04bcb158f80df89ac4d0d3f775a2ac0c87"}, + {file = "lxml-5.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:2996e1116bbb3ae2a1fbb2ba4da8f92742290b4011e7e5bce2bd33bbc9d9485a"}, + {file = "lxml-5.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:521ab9c80b98c30b2d987001c3ede2e647e92eeb2ca02e8cb66ef5122d792b24"}, + {file = "lxml-5.3.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f1231b0f9810289d41df1eacc4ebb859c63e4ceee29908a0217403cddce38d0"}, + {file = "lxml-5.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271f1a4d5d2b383c36ad8b9b489da5ea9c04eca795a215bae61ed6a57cf083cd"}, + {file = "lxml-5.3.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:6fca8a5a13906ba2677a5252752832beb0f483a22f6c86c71a2bb320fba04f61"}, + {file = "lxml-5.3.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ea0c3b7922209160faef194a5b6995bfe7fa05ff7dda6c423ba17646b7b9de10"}, + {file = "lxml-5.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0a006390834603e5952a2ff74b9a31a6007c7cc74282a087aa6467afb4eea987"}, + {file = "lxml-5.3.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:eae4136a3b8c4cf76f69461fc8f9410d55d34ea48e1185338848a888d71b9675"}, + {file = "lxml-5.3.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d48e06be8d8c58e7feaedd8a37897a6122637efb1637d7ce00ddf5f11f9a92ad"}, + {file = "lxml-5.3.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4b83aed409134093d90e114007034d2c1ebcd92e501b71fd9ec70e612c8b2eb"}, + {file = "lxml-5.3.2-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7a0e77edfe26d3703f954d46bed52c3ec55f58586f18f4b7f581fc56954f1d84"}, + {file = "lxml-5.3.2-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:19f6fcfd15b82036b4d235749d78785eb9c991c7812012dc084e0d8853b4c1c0"}, + {file = "lxml-5.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d49919c95d31ee06eefd43d8c6f69a3cc9bdf0a9b979cc234c4071f0eb5cb173"}, + {file = "lxml-5.3.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2d0a60841410123c533990f392819804a8448853f06daf412c0f383443925e89"}, + {file = "lxml-5.3.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b7f729e03090eb4e3981f10efaee35e6004b548636b1a062b8b9a525e752abc"}, + {file = "lxml-5.3.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:579df6e20d8acce3bcbc9fb8389e6ae00c19562e929753f534ba4c29cfe0be4b"}, + {file = "lxml-5.3.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2abcf3f3b8367d6400b908d00d4cd279fc0b8efa287e9043820525762d383699"}, + {file = "lxml-5.3.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:348c06cb2e3176ce98bee8c397ecc89181681afd13d85870df46167f140a305f"}, + {file = "lxml-5.3.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:617ecaccd565cbf1ac82ffcaa410e7da5bd3a4b892bb3543fb2fe19bd1c4467d"}, + {file = "lxml-5.3.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c3eb4278dcdb9d86265ed2c20b9ecac45f2d6072e3904542e591e382c87a9c00"}, + {file = "lxml-5.3.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:258b6b53458c5cbd2a88795557ff7e0db99f73a96601b70bc039114cd4ee9e02"}, + {file = "lxml-5.3.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0a9d8d25ed2f2183e8471c97d512a31153e123ac5807f61396158ef2793cb6e"}, + {file = "lxml-5.3.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:73bcb635a848c18a3e422ea0ab0092f2e4ef3b02d8ebe87ab49748ebc8ec03d8"}, + {file = "lxml-5.3.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1545de0a69a16ced5767bae8cca1801b842e6e49e96f5e4a8a5acbef023d970b"}, + {file = "lxml-5.3.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:165fcdc2f40fc0fe88a3c3c06c9c2a097388a90bda6a16e6f7c9199c903c9b8e"}, + {file = "lxml-5.3.2.tar.gz", hash = "sha256:773947d0ed809ddad824b7b14467e1a481b8976e87278ac4a730c2f7c7fcddc1"}, ] [package.extras] @@ -1596,104 +1594,104 @@ tests = ["pytest", "simplejson"] [[package]] name = "multidict" -version = "6.1.0" +version = "6.3.2" description = "multidict implementation" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, - {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, - {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, - {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, - {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, - {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, - {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, - {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, - {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, - {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, - {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, - {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, - {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, - {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, - {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, - {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, - {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, + {file = "multidict-6.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8b3dc0eec9304fa04d84a51ea13b0ec170bace5b7ddeaac748149efd316f1504"}, + {file = "multidict-6.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9534f3d84addd3b6018fa83f97c9d4247aaa94ac917d1ed7b2523306f99f5c16"}, + {file = "multidict-6.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a003ce1413ae01f0b8789c1c987991346a94620a4d22210f7a8fe753646d3209"}, + {file = "multidict-6.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b43f7384e68b1b982c99f489921a459467b5584bdb963b25e0df57c9039d0ad"}, + {file = "multidict-6.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d142ae84047262dc75c1f92eaf95b20680f85ce11d35571b4c97e267f96fadc4"}, + {file = "multidict-6.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec7e86fbc48aa1d6d686501a8547818ba8d645e7e40eaa98232a5d43ee4380ad"}, + {file = "multidict-6.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe019fb437632b016e6cac67a7e964f1ef827ef4023f1ca0227b54be354da97e"}, + {file = "multidict-6.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b60cb81214a9da7cfd8ae2853d5e6e47225ece55fe5833142fe0af321c35299"}, + {file = "multidict-6.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:32d9e8ef2e0312d4e96ca9adc88e0675b6d8e144349efce4a7c95d5ccb6d88e0"}, + {file = "multidict-6.3.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:335d584312e3fa43633d63175dfc1a5f137dd7aa03d38d1310237d54c3032774"}, + {file = "multidict-6.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:b8df917faa6b8cac3d6870fc21cb7e4d169faca68e43ffe568c156c9c6408a4d"}, + {file = "multidict-6.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:cc060b9b89b701dd8fedef5b99e1f1002b8cb95072693233a63389d37e48212d"}, + {file = "multidict-6.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f2ce3be2500658f3c644494b934628bb0c82e549dde250d2119689ce791cc8b8"}, + {file = "multidict-6.3.2-cp310-cp310-win32.whl", hash = "sha256:dbcb4490d8e74b484449abd51751b8f560dd0a4812eb5dacc6a588498222a9ab"}, + {file = "multidict-6.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:06944f9ced30f8602be873563ed4df7e3f40958f60b2db39732c11d615a33687"}, + {file = "multidict-6.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:45a034f41fcd16968c0470d8912d293d7b0d0822fc25739c5c2ff7835b85bc56"}, + {file = "multidict-6.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:352585cec45f5d83d886fc522955492bb436fca032b11d487b12d31c5a81b9e3"}, + {file = "multidict-6.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:da9d89d293511fd0a83a90559dc131f8b3292b6975eb80feff19e5f4663647e2"}, + {file = "multidict-6.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fa716592224aa652b9347a586cfe018635229074565663894eb4eb21f8307f"}, + {file = "multidict-6.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0326278a44c56e94792475268e5cd3d47fbc0bd41ee56928c3bbb103ba7f58fe"}, + {file = "multidict-6.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bb1ea87f7fe45e5079f6315e95d64d4ca8b43ef656d98bed63a02e3756853a22"}, + {file = "multidict-6.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cff3c5a98d037024a9065aafc621a8599fad7b423393685dc83cf7a32f8b691"}, + {file = "multidict-6.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed99834b053c655d980fb98029003cb24281e47a796052faad4543aa9e01b8e8"}, + {file = "multidict-6.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7048440e505d2b4741e5d0b32bd2f427c901f38c7760fc245918be2cf69b3b85"}, + {file = "multidict-6.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:27248c27b563f5889556da8a96e18e98a56ff807ac1a7d56cf4453c2c9e4cd91"}, + {file = "multidict-6.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6323b4ba0e018bd266f776c35f3f0943fc4ee77e481593c9f93bd49888f24e94"}, + {file = "multidict-6.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:81f7ce5ec7c27d0b45c10449c8f0fed192b93251e2e98cb0b21fec779ef1dc4d"}, + {file = "multidict-6.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03bfcf2825b3bed0ba08a9d854acd18b938cab0d2dba3372b51c78e496bac811"}, + {file = "multidict-6.3.2-cp311-cp311-win32.whl", hash = "sha256:f32c2790512cae6ca886920e58cdc8c784bdc4bb2a5ec74127c71980369d18dc"}, + {file = "multidict-6.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:0b0c15e58e038a2cd75ef7cf7e072bc39b5e0488b165902efb27978984bbad70"}, + {file = "multidict-6.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d1e0ba1ce1b8cc79117196642d95f4365e118eaf5fb85f57cdbcc5a25640b2a4"}, + {file = "multidict-6.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:029bbd7d782251a78975214b78ee632672310f9233d49531fc93e8e99154af25"}, + {file = "multidict-6.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d7db41e3b56817d9175264e5fe00192fbcb8e1265307a59f53dede86161b150e"}, + {file = "multidict-6.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fcab18e65cc555ac29981a581518c23311f2b1e72d8f658f9891590465383be"}, + {file = "multidict-6.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d50eff89aa4d145a5486b171a2177042d08ea5105f813027eb1050abe91839f"}, + {file = "multidict-6.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:643e57b403d3e240045a3681f9e6a04d35a33eddc501b4cbbbdbc9c70122e7bc"}, + {file = "multidict-6.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d17b37b9715b30605b5bab1460569742d0c309e5c20079263b440f5d7746e7e"}, + {file = "multidict-6.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68acd51fa94e63312b8ddf84bfc9c3d3442fe1f9988bbe1b6c703043af8867fe"}, + {file = "multidict-6.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:347eea2852ab7f697cc5ed9b1aae96b08f8529cca0c6468f747f0781b1842898"}, + {file = "multidict-6.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4d3f8e57027dcda84a1aa181501c15c45eab9566eb6fcc274cbd1e7561224f8"}, + {file = "multidict-6.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9ca57a841ffcf712e47875d026aa49d6e67f9560624d54b51628603700d5d287"}, + {file = "multidict-6.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7cafdafb44c4e646118410368307693e49d19167e5f119cbe3a88697d2d1a636"}, + {file = "multidict-6.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:430120c6ce3715a9c6075cabcee557daccbcca8ba25a9fedf05c7bf564532f2d"}, + {file = "multidict-6.3.2-cp312-cp312-win32.whl", hash = "sha256:13bec31375235a68457ab887ce1bbf4f59d5810d838ae5d7e5b416242e1f3ed4"}, + {file = "multidict-6.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:c3b6d7620e6e90c6d97eaf3a63bf7fbd2ba253aab89120a4a9c660bf2d675391"}, + {file = "multidict-6.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:b9ca24700322816ae0d426aa33671cf68242f8cc85cee0d0e936465ddaee90b5"}, + {file = "multidict-6.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d9fbbe23667d596ff4f9f74d44b06e40ebb0ab6b262cf14a284f859a66f86457"}, + {file = "multidict-6.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9cb602c5bea0589570ad3a4a6f2649c4f13cc7a1e97b4c616e5e9ff8dc490987"}, + {file = "multidict-6.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93ca81dd4d1542e20000ed90f4cc84b7713776f620d04c2b75b8efbe61106c99"}, + {file = "multidict-6.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:18b6310b5454c62242577a128c87df8897f39dd913311cf2e1298e47dfc089eb"}, + {file = "multidict-6.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7a6dda57de1fc9aedfdb600a8640c99385cdab59a5716cb714b52b6005797f77"}, + {file = "multidict-6.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d8ec42d03cc6b29845552a68151f9e623c541f1708328353220af571e24a247"}, + {file = "multidict-6.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80681969cee2fa84dafeb53615d51d24246849984e3e87fbe4fe39956f2e23bf"}, + {file = "multidict-6.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:01489b0c3592bb9d238e5690e9566db7f77a5380f054b57077d2c4deeaade0eb"}, + {file = "multidict-6.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:522d9f1fd995d04dfedc0a40bca7e2591bc577d920079df50b56245a4a252c1c"}, + {file = "multidict-6.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:2014e9cf0b4e9c75bbad49c1758e5a9bf967a56184fc5fcc51527425baf5abba"}, + {file = "multidict-6.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:78ced9fcbee79e446ff4bb3018ac7ba1670703de7873d9c1f6f9883db53c71bc"}, + {file = "multidict-6.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1faf01af972bd01216a107c195f5294f9f393531bc3e4faddc9b333581255d4d"}, + {file = "multidict-6.3.2-cp313-cp313-win32.whl", hash = "sha256:7a699ab13d8d8e1f885de1535b4f477fb93836c87168318244c2685da7b7f655"}, + {file = "multidict-6.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:8666bb0d883310c83be01676e302587834dfd185b52758caeab32ef0eb387bc6"}, + {file = "multidict-6.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:d82c95aabee29612b1c4f48b98be98181686eb7d6c0152301f72715705cc787b"}, + {file = "multidict-6.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f47709173ea9e87a7fd05cd7e5cf1e5d4158924ff988a9a8e0fbd853705f0e68"}, + {file = "multidict-6.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0c7f9d0276ceaab41b8ae78534ff28ea33d5de85db551cbf80c44371f2b55d13"}, + {file = "multidict-6.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6eab22df44a25acab2e738f882f5ec551282ab45b2bbda5301e6d2cfb323036"}, + {file = "multidict-6.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a947cb7c657f57874021b9b70c7aac049c877fb576955a40afa8df71d01a1390"}, + {file = "multidict-6.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5faa346e8e1c371187cf345ab1e02a75889f9f510c9cbc575c31b779f7df084d"}, + {file = "multidict-6.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc6e08d977aebf1718540533b4ba5b351ccec2db093370958a653b1f7f9219cc"}, + {file = "multidict-6.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:98eab7acf55275b5bf09834125fa3a80b143a9f241cdcdd3f1295ffdc3c6d097"}, + {file = "multidict-6.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:36863655630becc224375c0b99364978a0f95aebfb27fb6dd500f7fb5fb36e79"}, + {file = "multidict-6.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d9c0979c096c0d46a963331b0e400d3a9e560e41219df4b35f0d7a2f28f39710"}, + {file = "multidict-6.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0efc04f70f05e70e5945890767e8874da5953a196f5b07c552d305afae0f3bf6"}, + {file = "multidict-6.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:2c519b3b82c34539fae3e22e4ea965869ac6b628794b1eb487780dde37637ab7"}, + {file = "multidict-6.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:329160e301f2afd7b43725d3dda8a7ef8ee41d4ceac2083fc0d8c1cc8a4bd56b"}, + {file = "multidict-6.3.2-cp313-cp313t-win32.whl", hash = "sha256:420e5144a5f598dad8db3128f1695cd42a38a0026c2991091dab91697832f8cc"}, + {file = "multidict-6.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:875faded2861c7af2682c67088e6313fec35ede811e071c96d36b081873cea14"}, + {file = "multidict-6.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2516c5eb5732d6c4e29fa93323bfdc55186895124bc569e2404e3820934be378"}, + {file = "multidict-6.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:be5c8622e665cc5491c13c0fcd52915cdbae991a3514251d71129691338cdfb2"}, + {file = "multidict-6.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3ef33150eea7953cfdb571d862cff894e0ad97ab80d97731eb4b9328fc32d52b"}, + {file = "multidict-6.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40b357738ce46e998f1b1bad9c4b79b2a9755915f71b87a8c01ce123a22a4f99"}, + {file = "multidict-6.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:27c60e059fcd3655a653ba99fec2556cd0260ec57f9cb138d3e6ffc413638a2e"}, + {file = "multidict-6.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:629e7c5e75bde83e54a22c7043ce89d68691d1f103be6d09a1c82b870df3b4b8"}, + {file = "multidict-6.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6c8fc97d893fdf1fff15a619fee8de2f31c9b289ef7594730e35074fa0cefb"}, + {file = "multidict-6.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52081d2f27e0652265d4637b03f09b82f6da5ce5e1474f07dc64674ff8bfc04c"}, + {file = "multidict-6.3.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:64529dc395b5fd0a7826ffa70d2d9a7f4abd8f5333d6aaaba67fdf7bedde9f21"}, + {file = "multidict-6.3.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2b7c3fad827770840f5399348c89635ed6d6e9bba363baad7d3c7f86a9cf1da3"}, + {file = "multidict-6.3.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:24aa42b1651c654ae9e5273e06c3b7ccffe9f7cc76fbde40c37e9ae65f170818"}, + {file = "multidict-6.3.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:04ceea01e9991357164b12882e120ce6b4d63a0424bb9f9cd37910aa56d30830"}, + {file = "multidict-6.3.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:943897a41160945416617db567d867ab34e9258adaffc56a25a4c3f99d919598"}, + {file = "multidict-6.3.2-cp39-cp39-win32.whl", hash = "sha256:76157a9a0c5380aadd3b5ff7b8deee355ff5adecc66c837b444fa633b4d409a2"}, + {file = "multidict-6.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:d091d123e44035cd5664554308477aff0b58db37e701e7598a67e907b98d1925"}, + {file = "multidict-6.3.2-py3-none-any.whl", hash = "sha256:71409d4579f716217f23be2f5e7afca5ca926aaeb398aa11b72d793bff637a1f"}, + {file = "multidict-6.3.2.tar.gz", hash = "sha256:c1035eea471f759fa853dd6e76aaa1e389f93b3e1403093fa0fd3ab4db490678"}, ] [[package]] @@ -1863,20 +1861,20 @@ xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "4.3.6" +version = "4.3.7" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, - {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, + {file = "platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94"}, + {file = "platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351"}, ] [package.extras] -docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] -type = ["mypy (>=1.11.2)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.14.1)"] [[package]] name = "pluggy" @@ -1962,110 +1960,110 @@ wcwidth = "*" [[package]] name = "propcache" -version = "0.3.0" +version = "0.3.1" description = "Accelerated property cache" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:efa44f64c37cc30c9f05932c740a8b40ce359f51882c70883cc95feac842da4d"}, - {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2383a17385d9800b6eb5855c2f05ee550f803878f344f58b6e194de08b96352c"}, - {file = "propcache-0.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3e7420211f5a65a54675fd860ea04173cde60a7cc20ccfbafcccd155225f8bc"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3302c5287e504d23bb0e64d2a921d1eb4a03fb93a0a0aa3b53de059f5a5d737d"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e2e068a83552ddf7a39a99488bcba05ac13454fb205c847674da0352602082f"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d913d36bdaf368637b4f88d554fb9cb9d53d6920b9c5563846555938d5450bf"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ee1983728964d6070ab443399c476de93d5d741f71e8f6e7880a065f878e0b9"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:36ca5e9a21822cc1746023e88f5c0af6fce3af3b85d4520efb1ce4221bed75cc"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9ecde3671e62eeb99e977f5221abcf40c208f69b5eb986b061ccec317c82ebd0"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d383bf5e045d7f9d239b38e6acadd7b7fdf6c0087259a84ae3475d18e9a2ae8b"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8cb625bcb5add899cb8ba7bf716ec1d3e8f7cdea9b0713fa99eadf73b6d4986f"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5fa159dcee5dba00c1def3231c249cf261185189205073bde13797e57dd7540a"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a7080b0159ce05f179cfac592cda1a82898ca9cd097dacf8ea20ae33474fbb25"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ed7161bccab7696a473fe7ddb619c1d75963732b37da4618ba12e60899fefe4f"}, - {file = "propcache-0.3.0-cp310-cp310-win32.whl", hash = "sha256:bf0d9a171908f32d54f651648c7290397b8792f4303821c42a74e7805bfb813c"}, - {file = "propcache-0.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:42924dc0c9d73e49908e35bbdec87adedd651ea24c53c29cac103ede0ea1d340"}, - {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9ddd49258610499aab83b4f5b61b32e11fce873586282a0e972e5ab3bcadee51"}, - {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2578541776769b500bada3f8a4eeaf944530516b6e90c089aa368266ed70c49e"}, - {file = "propcache-0.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8074c5dd61c8a3e915fa8fc04754fa55cfa5978200d2daa1e2d4294c1f136aa"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b58229a844931bca61b3a20efd2be2a2acb4ad1622fc026504309a6883686fbf"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e45377d5d6fefe1677da2a2c07b024a6dac782088e37c0b1efea4cfe2b1be19b"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec5060592d83454e8063e487696ac3783cc48c9a329498bafae0d972bc7816c9"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15010f29fbed80e711db272909a074dc79858c6d28e2915704cfc487a8ac89c6"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a254537b9b696ede293bfdbc0a65200e8e4507bc9f37831e2a0318a9b333c85c"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2b975528998de037dfbc10144b8aed9b8dd5a99ec547f14d1cb7c5665a43f075"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:19d36bb351ad5554ff20f2ae75f88ce205b0748c38b146c75628577020351e3c"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6032231d4a5abd67c7f71168fd64a47b6b451fbcb91c8397c2f7610e67683810"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6985a593417cdbc94c7f9c3403747335e450c1599da1647a5af76539672464d3"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6a1948df1bb1d56b5e7b0553c0fa04fd0e320997ae99689488201f19fa90d2e7"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8319293e85feadbbfe2150a5659dbc2ebc4afdeaf7d98936fb9a2f2ba0d4c35c"}, - {file = "propcache-0.3.0-cp311-cp311-win32.whl", hash = "sha256:63f26258a163c34542c24808f03d734b338da66ba91f410a703e505c8485791d"}, - {file = "propcache-0.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:cacea77ef7a2195f04f9279297684955e3d1ae4241092ff0cfcef532bb7a1c32"}, - {file = "propcache-0.3.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e53d19c2bf7d0d1e6998a7e693c7e87300dd971808e6618964621ccd0e01fe4e"}, - {file = "propcache-0.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a61a68d630e812b67b5bf097ab84e2cd79b48c792857dc10ba8a223f5b06a2af"}, - {file = "propcache-0.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fb91d20fa2d3b13deea98a690534697742029f4fb83673a3501ae6e3746508b5"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67054e47c01b7b349b94ed0840ccae075449503cf1fdd0a1fdd98ab5ddc2667b"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997e7b8f173a391987df40f3b52c423e5850be6f6df0dcfb5376365440b56667"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d663fd71491dde7dfdfc899d13a067a94198e90695b4321084c6e450743b8c7"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8884ba1a0fe7210b775106b25850f5e5a9dc3c840d1ae9924ee6ea2eb3acbfe7"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa806bbc13eac1ab6291ed21ecd2dd426063ca5417dd507e6be58de20e58dfcf"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6f4d7a7c0aff92e8354cceca6fe223973ddf08401047920df0fcb24be2bd5138"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9be90eebc9842a93ef8335291f57b3b7488ac24f70df96a6034a13cb58e6ff86"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bf15fc0b45914d9d1b706f7c9c4f66f2b7b053e9517e40123e137e8ca8958b3d"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5a16167118677d94bb48bfcd91e420088854eb0737b76ec374b91498fb77a70e"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:41de3da5458edd5678b0f6ff66691507f9885f5fe6a0fb99a5d10d10c0fd2d64"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:728af36011bb5d344c4fe4af79cfe186729efb649d2f8b395d1572fb088a996c"}, - {file = "propcache-0.3.0-cp312-cp312-win32.whl", hash = "sha256:6b5b7fd6ee7b54e01759f2044f936dcf7dea6e7585f35490f7ca0420fe723c0d"}, - {file = "propcache-0.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:2d15bc27163cd4df433e75f546b9ac31c1ba7b0b128bfb1b90df19082466ff57"}, - {file = "propcache-0.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a2b9bf8c79b660d0ca1ad95e587818c30ccdb11f787657458d6f26a1ea18c568"}, - {file = "propcache-0.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0c1a133d42c6fc1f5fbcf5c91331657a1ff822e87989bf4a6e2e39b818d0ee9"}, - {file = "propcache-0.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bb2f144c6d98bb5cbc94adeb0447cfd4c0f991341baa68eee3f3b0c9c0e83767"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1323cd04d6e92150bcc79d0174ce347ed4b349d748b9358fd2e497b121e03c8"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b812b3cb6caacd072276ac0492d249f210006c57726b6484a1e1805b3cfeea0"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:742840d1d0438eb7ea4280f3347598f507a199a35a08294afdcc560c3739989d"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c6e7e4f9167fddc438cd653d826f2222222564daed4116a02a184b464d3ef05"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a94ffc66738da99232ddffcf7910e0f69e2bbe3a0802e54426dbf0714e1c2ffe"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c6ec957025bf32b15cbc6b67afe233c65b30005e4c55fe5768e4bb518d712f1"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:549722908de62aa0b47a78b90531c022fa6e139f9166be634f667ff45632cc92"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5d62c4f6706bff5d8a52fd51fec6069bef69e7202ed481486c0bc3874912c787"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:24c04f8fbf60094c531667b8207acbae54146661657a1b1be6d3ca7773b7a545"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7c5f5290799a3f6539cc5e6f474c3e5c5fbeba74a5e1e5be75587746a940d51e"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4fa0e7c9c3cf7c276d4f6ab9af8adddc127d04e0fcabede315904d2ff76db626"}, - {file = "propcache-0.3.0-cp313-cp313-win32.whl", hash = "sha256:ee0bd3a7b2e184e88d25c9baa6a9dc609ba25b76daae942edfb14499ac7ec374"}, - {file = "propcache-0.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1c8f7d896a16da9455f882870a507567d4f58c53504dc2d4b1e1d386dfe4588a"}, - {file = "propcache-0.3.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e560fd75aaf3e5693b91bcaddd8b314f4d57e99aef8a6c6dc692f935cc1e6bbf"}, - {file = "propcache-0.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:65a37714b8ad9aba5780325228598a5b16c47ba0f8aeb3dc0514701e4413d7c0"}, - {file = "propcache-0.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:07700939b2cbd67bfb3b76a12e1412405d71019df00ca5697ce75e5ef789d829"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c0fdbdf6983526e269e5a8d53b7ae3622dd6998468821d660d0daf72779aefa"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:794c3dd744fad478b6232289c866c25406ecdfc47e294618bdf1697e69bd64a6"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4544699674faf66fb6b4473a1518ae4999c1b614f0b8297b1cef96bac25381db"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fddb8870bdb83456a489ab67c6b3040a8d5a55069aa6f72f9d872235fbc52f54"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f857034dc68d5ceb30fb60afb6ff2103087aea10a01b613985610e007053a121"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:02df07041e0820cacc8f739510078f2aadcfd3fc57eaeeb16d5ded85c872c89e"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f47d52fd9b2ac418c4890aad2f6d21a6b96183c98021f0a48497a904199f006e"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9ff4e9ecb6e4b363430edf2c6e50173a63e0820e549918adef70515f87ced19a"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ecc2920630283e0783c22e2ac94427f8cca29a04cfdf331467d4f661f4072dac"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:c441c841e82c5ba7a85ad25986014be8d7849c3cfbdb6004541873505929a74e"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c929916cbdb540d3407c66f19f73387f43e7c12fa318a66f64ac99da601bcdf"}, - {file = "propcache-0.3.0-cp313-cp313t-win32.whl", hash = "sha256:0c3e893c4464ebd751b44ae76c12c5f5c1e4f6cbd6fbf67e3783cd93ad221863"}, - {file = "propcache-0.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:75e872573220d1ee2305b35c9813626e620768248425f58798413e9c39741f46"}, - {file = "propcache-0.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:03c091bb752349402f23ee43bb2bff6bd80ccab7c9df6b88ad4322258d6960fc"}, - {file = "propcache-0.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:46ed02532cb66612d42ae5c3929b5e98ae330ea0f3900bc66ec5f4862069519b"}, - {file = "propcache-0.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11ae6a8a01b8a4dc79093b5d3ca2c8a4436f5ee251a9840d7790dccbd96cb649"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df03cd88f95b1b99052b52b1bb92173229d7a674df0ab06d2b25765ee8404bce"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03acd9ff19021bd0567582ac88f821b66883e158274183b9e5586f678984f8fe"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd54895e4ae7d32f1e3dd91261df46ee7483a735017dc6f987904f194aa5fd14"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26a67e5c04e3119594d8cfae517f4b9330c395df07ea65eab16f3d559b7068fe"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee25f1ac091def37c4b59d192bbe3a206298feeb89132a470325bf76ad122a1e"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:58e6d2a5a7cb3e5f166fd58e71e9a4ff504be9dc61b88167e75f835da5764d07"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:be90c94570840939fecedf99fa72839aed70b0ced449b415c85e01ae67422c90"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:49ea05212a529c2caffe411e25a59308b07d6e10bf2505d77da72891f9a05641"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:119e244ab40f70a98c91906d4c1f4c5f2e68bd0b14e7ab0a06922038fae8a20f"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:507c5357a8d8b4593b97fb669c50598f4e6cccbbf77e22fa9598aba78292b4d7"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8526b0941ec5a40220fc4dfde76aed58808e2b309c03e9fa8e2260083ef7157f"}, - {file = "propcache-0.3.0-cp39-cp39-win32.whl", hash = "sha256:7cedd25e5f678f7738da38037435b340694ab34d424938041aa630d8bac42663"}, - {file = "propcache-0.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:bf4298f366ca7e1ad1d21bbb58300a6985015909964077afd37559084590c929"}, - {file = "propcache-0.3.0-py3-none-any.whl", hash = "sha256:67dda3c7325691c2081510e92c561f465ba61b975f481735aefdfc845d2cd043"}, - {file = "propcache-0.3.0.tar.gz", hash = "sha256:a8fd93de4e1d278046345f49e2238cdb298589325849b2645d4a94c53faeffc5"}, + {file = "propcache-0.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f27785888d2fdd918bc36de8b8739f2d6c791399552333721b58193f68ea3e98"}, + {file = "propcache-0.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4e89cde74154c7b5957f87a355bb9c8ec929c167b59c83d90654ea36aeb6180"}, + {file = "propcache-0.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:730178f476ef03d3d4d255f0c9fa186cb1d13fd33ffe89d39f2cda4da90ceb71"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:967a8eec513dbe08330f10137eacb427b2ca52118769e82ebcfcab0fba92a649"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b9145c35cc87313b5fd480144f8078716007656093d23059e8993d3a8fa730f"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e64e948ab41411958670f1093c0a57acfdc3bee5cf5b935671bbd5313bcf229"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:319fa8765bfd6a265e5fa661547556da381e53274bc05094fc9ea50da51bfd46"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66d8ccbc902ad548312b96ed8d5d266d0d2c6d006fd0f66323e9d8f2dd49be7"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2d219b0dbabe75e15e581fc1ae796109b07c8ba7d25b9ae8d650da582bed01b0"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:cd6a55f65241c551eb53f8cf4d2f4af33512c39da5d9777694e9d9c60872f519"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9979643ffc69b799d50d3a7b72b5164a2e97e117009d7af6dfdd2ab906cb72cd"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4cf9e93a81979f1424f1a3d155213dc928f1069d697e4353edb8a5eba67c6259"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2fce1df66915909ff6c824bbb5eb403d2d15f98f1518e583074671a30fe0c21e"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4d0dfdd9a2ebc77b869a0b04423591ea8823f791293b527dc1bb896c1d6f1136"}, + {file = "propcache-0.3.1-cp310-cp310-win32.whl", hash = "sha256:1f6cc0ad7b4560e5637eb2c994e97b4fa41ba8226069c9277eb5ea7101845b42"}, + {file = "propcache-0.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:47ef24aa6511e388e9894ec16f0fbf3313a53ee68402bc428744a367ec55b833"}, + {file = "propcache-0.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7f30241577d2fef2602113b70ef7231bf4c69a97e04693bde08ddab913ba0ce5"}, + {file = "propcache-0.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:43593c6772aa12abc3af7784bff4a41ffa921608dd38b77cf1dfd7f5c4e71371"}, + {file = "propcache-0.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a75801768bbe65499495660b777e018cbe90c7980f07f8aa57d6be79ea6f71da"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6f1324db48f001c2ca26a25fa25af60711e09b9aaf4b28488602776f4f9a744"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cdb0f3e1eb6dfc9965d19734d8f9c481b294b5274337a8cb5cb01b462dcb7e0"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1eb34d90aac9bfbced9a58b266f8946cb5935869ff01b164573a7634d39fbcb5"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f35c7070eeec2cdaac6fd3fe245226ed2a6292d3ee8c938e5bb645b434c5f256"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b23c11c2c9e6d4e7300c92e022046ad09b91fd00e36e83c44483df4afa990073"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3e19ea4ea0bf46179f8a3652ac1426e6dcbaf577ce4b4f65be581e237340420d"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:bd39c92e4c8f6cbf5f08257d6360123af72af9f4da75a690bef50da77362d25f"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b0313e8b923b3814d1c4a524c93dfecea5f39fa95601f6a9b1ac96cd66f89ea0"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e861ad82892408487be144906a368ddbe2dc6297074ade2d892341b35c59844a"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:61014615c1274df8da5991a1e5da85a3ccb00c2d4701ac6f3383afd3ca47ab0a"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:71ebe3fe42656a2328ab08933d420df5f3ab121772eef78f2dc63624157f0ed9"}, + {file = "propcache-0.3.1-cp311-cp311-win32.whl", hash = "sha256:58aa11f4ca8b60113d4b8e32d37e7e78bd8af4d1a5b5cb4979ed856a45e62005"}, + {file = "propcache-0.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:9532ea0b26a401264b1365146c440a6d78269ed41f83f23818d4b79497aeabe7"}, + {file = "propcache-0.3.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f78eb8422acc93d7b69964012ad7048764bb45a54ba7a39bb9e146c72ea29723"}, + {file = "propcache-0.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:89498dd49c2f9a026ee057965cdf8192e5ae070ce7d7a7bd4b66a8e257d0c976"}, + {file = "propcache-0.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:09400e98545c998d57d10035ff623266927cb784d13dd2b31fd33b8a5316b85b"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa8efd8c5adc5a2c9d3b952815ff8f7710cefdcaf5f2c36d26aff51aeca2f12f"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2fe5c910f6007e716a06d269608d307b4f36e7babee5f36533722660e8c4a70"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a0ab8cf8cdd2194f8ff979a43ab43049b1df0b37aa64ab7eca04ac14429baeb7"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:563f9d8c03ad645597b8d010ef4e9eab359faeb11a0a2ac9f7b4bc8c28ebef25"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb6e0faf8cb6b4beea5d6ed7b5a578254c6d7df54c36ccd3d8b3eb00d6770277"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1c5c7ab7f2bb3f573d1cb921993006ba2d39e8621019dffb1c5bc94cdbae81e8"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:050b571b2e96ec942898f8eb46ea4bfbb19bd5502424747e83badc2d4a99a44e"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e1c4d24b804b3a87e9350f79e2371a705a188d292fd310e663483af6ee6718ee"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e4fe2a6d5ce975c117a6bb1e8ccda772d1e7029c1cca1acd209f91d30fa72815"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:feccd282de1f6322f56f6845bf1207a537227812f0a9bf5571df52bb418d79d5"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ec314cde7314d2dd0510c6787326bbffcbdc317ecee6b7401ce218b3099075a7"}, + {file = "propcache-0.3.1-cp312-cp312-win32.whl", hash = "sha256:7d2d5a0028d920738372630870e7d9644ce437142197f8c827194fca404bf03b"}, + {file = "propcache-0.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:88c423efef9d7a59dae0614eaed718449c09a5ac79a5f224a8b9664d603f04a3"}, + {file = "propcache-0.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f1528ec4374617a7a753f90f20e2f551121bb558fcb35926f99e3c42367164b8"}, + {file = "propcache-0.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dc1915ec523b3b494933b5424980831b636fe483d7d543f7afb7b3bf00f0c10f"}, + {file = "propcache-0.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a110205022d077da24e60b3df8bcee73971be9575dec5573dd17ae5d81751111"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d249609e547c04d190e820d0d4c8ca03ed4582bcf8e4e160a6969ddfb57b62e5"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ced33d827625d0a589e831126ccb4f5c29dfdf6766cac441d23995a65825dcb"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4114c4ada8f3181af20808bedb250da6bae56660e4b8dfd9cd95d4549c0962f7"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:975af16f406ce48f1333ec5e912fe11064605d5c5b3f6746969077cc3adeb120"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a34aa3a1abc50740be6ac0ab9d594e274f59960d3ad253cd318af76b996dd654"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9cec3239c85ed15bfaded997773fdad9fb5662b0a7cbc854a43f291eb183179e"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:05543250deac8e61084234d5fc54f8ebd254e8f2b39a16b1dce48904f45b744b"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5cb5918253912e088edbf023788de539219718d3b10aef334476b62d2b53de53"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f3bbecd2f34d0e6d3c543fdb3b15d6b60dd69970c2b4c822379e5ec8f6f621d5"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aca63103895c7d960a5b9b044a83f544b233c95e0dcff114389d64d762017af7"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a0a9898fdb99bf11786265468571e628ba60af80dc3f6eb89a3545540c6b0ef"}, + {file = "propcache-0.3.1-cp313-cp313-win32.whl", hash = "sha256:3a02a28095b5e63128bcae98eb59025924f121f048a62393db682f049bf4ac24"}, + {file = "propcache-0.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037"}, + {file = "propcache-0.3.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a444192f20f5ce8a5e52761a031b90f5ea6288b1eef42ad4c7e64fef33540b8f"}, + {file = "propcache-0.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fbe94666e62ebe36cd652f5fc012abfbc2342de99b523f8267a678e4dfdee3c"}, + {file = "propcache-0.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f011f104db880f4e2166bcdcf7f58250f7a465bc6b068dc84c824a3d4a5c94dc"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e584b6d388aeb0001d6d5c2bd86b26304adde6d9bb9bfa9c4889805021b96de"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a17583515a04358b034e241f952f1715243482fc2c2945fd99a1b03a0bd77d6"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5aed8d8308215089c0734a2af4f2e95eeb360660184ad3912686c181e500b2e7"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d8e309ff9a0503ef70dc9a0ebd3e69cf7b3894c9ae2ae81fc10943c37762458"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b655032b202028a582d27aeedc2e813299f82cb232f969f87a4fde491a233f11"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f64d91b751df77931336b5ff7bafbe8845c5770b06630e27acd5dbb71e1931c"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:19a06db789a4bd896ee91ebc50d059e23b3639c25d58eb35be3ca1cbe967c3bf"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:bef100c88d8692864651b5f98e871fb090bd65c8a41a1cb0ff2322db39c96c27"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:87380fb1f3089d2a0b8b00f006ed12bd41bd858fabfa7330c954c70f50ed8757"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e474fc718e73ba5ec5180358aa07f6aded0ff5f2abe700e3115c37d75c947e18"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:17d1c688a443355234f3c031349da69444be052613483f3e4158eef751abcd8a"}, + {file = "propcache-0.3.1-cp313-cp313t-win32.whl", hash = "sha256:359e81a949a7619802eb601d66d37072b79b79c2505e6d3fd8b945538411400d"}, + {file = "propcache-0.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e7fb9a84c9abbf2b2683fa3e7b0d7da4d8ecf139a1c635732a8bda29c5214b0e"}, + {file = "propcache-0.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ed5f6d2edbf349bd8d630e81f474d33d6ae5d07760c44d33cd808e2f5c8f4ae6"}, + {file = "propcache-0.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:668ddddc9f3075af019f784456267eb504cb77c2c4bd46cc8402d723b4d200bf"}, + {file = "propcache-0.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0c86e7ceea56376216eba345aa1fc6a8a6b27ac236181f840d1d7e6a1ea9ba5c"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83be47aa4e35b87c106fc0c84c0fc069d3f9b9b06d3c494cd404ec6747544894"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:27c6ac6aa9fc7bc662f594ef380707494cb42c22786a558d95fcdedb9aa5d035"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a956dff37080b352c1c40b2966b09defb014347043e740d420ca1eb7c9b908"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82de5da8c8893056603ac2d6a89eb8b4df49abf1a7c19d536984c8dd63f481d5"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c3c3a203c375b08fd06a20da3cf7aac293b834b6f4f4db71190e8422750cca5"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b303b194c2e6f171cfddf8b8ba30baefccf03d36a4d9cab7fd0bb68ba476a3d7"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:916cd229b0150129d645ec51614d38129ee74c03293a9f3f17537be0029a9641"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:a461959ead5b38e2581998700b26346b78cd98540b5524796c175722f18b0294"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:069e7212890b0bcf9b2be0a03afb0c2d5161d91e1bf51569a64f629acc7defbf"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ef2e4e91fb3945769e14ce82ed53007195e616a63aa43b40fb7ebaaf907c8d4c"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8638f99dca15b9dff328fb6273e09f03d1c50d9b6512f3b65a4154588a7595fe"}, + {file = "propcache-0.3.1-cp39-cp39-win32.whl", hash = "sha256:6f173bbfe976105aaa890b712d1759de339d8a7cef2fc0a1714cc1a1e1c47f64"}, + {file = "propcache-0.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:603f1fe4144420374f1a69b907494c3acbc867a581c2d49d4175b0de7cc64566"}, + {file = "propcache-0.3.1-py3-none-any.whl", hash = "sha256:9a8ecf38de50a7f518c21568c80f985e776397b902f1ce0b01f799aba1608b40"}, + {file = "propcache-0.3.1.tar.gz", hash = "sha256:40d980c33765359098837527e18eddefc9a24cea5b45e078a7f3bb5b032c6ecf"}, ] [[package]] @@ -2082,20 +2080,21 @@ files = [ [[package]] name = "pydantic" -version = "2.10.6" +version = "2.11.2" description = "Data validation using Python type hints" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"}, - {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"}, + {file = "pydantic-2.11.2-py3-none-any.whl", hash = "sha256:7f17d25846bcdf89b670a86cdfe7b29a9f1c9ca23dee154221c9aa81845cfca7"}, + {file = "pydantic-2.11.2.tar.gz", hash = "sha256:2138628e050bd7a1e70b91d4bf4a91167f4ad76fdb83209b107c8d84b854917e"}, ] [package.dependencies] annotated-types = ">=0.6.0" -pydantic-core = "2.27.2" +pydantic-core = "2.33.1" typing-extensions = ">=4.12.2" +typing-inspection = ">=0.4.0" [package.extras] email = ["email-validator (>=2.0.0)"] @@ -2103,112 +2102,111 @@ timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows [[package]] name = "pydantic-core" -version = "2.27.2" +version = "2.33.1" description = "Core functionality for Pydantic validation and serialization" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, - {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236"}, - {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962"}, - {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9"}, - {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af"}, - {file = "pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4"}, - {file = "pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31"}, - {file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"}, - {file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"}, - {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"}, - {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"}, - {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"}, - {file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"}, - {file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"}, - {file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"}, - {file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"}, - {file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"}, - {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"}, - {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"}, - {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"}, - {file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"}, - {file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"}, - {file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"}, - {file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"}, - {file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"}, - {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"}, - {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"}, - {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"}, - {file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"}, - {file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"}, - {file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"}, - {file = "pydantic_core-2.27.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506"}, - {file = "pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a"}, - {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d"}, - {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9"}, - {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da"}, - {file = "pydantic_core-2.27.2-cp38-cp38-win32.whl", hash = "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b"}, - {file = "pydantic_core-2.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad"}, - {file = "pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993"}, - {file = "pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54"}, - {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f"}, - {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362"}, - {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96"}, - {file = "pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e"}, - {file = "pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35"}, - {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"}, + {file = "pydantic_core-2.33.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3077cfdb6125cc8dab61b155fdd714663e401f0e6883f9632118ec12cf42df26"}, + {file = "pydantic_core-2.33.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8ffab8b2908d152e74862d276cf5017c81a2f3719f14e8e3e8d6b83fda863927"}, + {file = "pydantic_core-2.33.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5183e4f6a2d468787243ebcd70cf4098c247e60d73fb7d68d5bc1e1beaa0c4db"}, + {file = "pydantic_core-2.33.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:398a38d323f37714023be1e0285765f0a27243a8b1506b7b7de87b647b517e48"}, + {file = "pydantic_core-2.33.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:87d3776f0001b43acebfa86f8c64019c043b55cc5a6a2e313d728b5c95b46969"}, + {file = "pydantic_core-2.33.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c566dd9c5f63d22226409553531f89de0cac55397f2ab8d97d6f06cfce6d947e"}, + {file = "pydantic_core-2.33.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0d5f3acc81452c56895e90643a625302bd6be351e7010664151cc55b7b97f89"}, + {file = "pydantic_core-2.33.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d3a07fadec2a13274a8d861d3d37c61e97a816beae717efccaa4b36dfcaadcde"}, + {file = "pydantic_core-2.33.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f99aeda58dce827f76963ee87a0ebe75e648c72ff9ba1174a253f6744f518f65"}, + {file = "pydantic_core-2.33.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:902dbc832141aa0ec374f4310f1e4e7febeebc3256f00dc359a9ac3f264a45dc"}, + {file = "pydantic_core-2.33.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fe44d56aa0b00d66640aa84a3cbe80b7a3ccdc6f0b1ca71090696a6d4777c091"}, + {file = "pydantic_core-2.33.1-cp310-cp310-win32.whl", hash = "sha256:ed3eb16d51257c763539bde21e011092f127a2202692afaeaccb50db55a31383"}, + {file = "pydantic_core-2.33.1-cp310-cp310-win_amd64.whl", hash = "sha256:694ad99a7f6718c1a498dc170ca430687a39894a60327f548e02a9c7ee4b6504"}, + {file = "pydantic_core-2.33.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6e966fc3caaf9f1d96b349b0341c70c8d6573bf1bac7261f7b0ba88f96c56c24"}, + {file = "pydantic_core-2.33.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bfd0adeee563d59c598ceabddf2c92eec77abcb3f4a391b19aa7366170bd9e30"}, + {file = "pydantic_core-2.33.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91815221101ad3c6b507804178a7bb5cb7b2ead9ecd600041669c8d805ebd595"}, + {file = "pydantic_core-2.33.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9fea9c1869bb4742d174a57b4700c6dadea951df8b06de40c2fedb4f02931c2e"}, + {file = "pydantic_core-2.33.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d20eb4861329bb2484c021b9d9a977566ab16d84000a57e28061151c62b349a"}, + {file = "pydantic_core-2.33.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb935c5591573ae3201640579f30128ccc10739b45663f93c06796854405505"}, + {file = "pydantic_core-2.33.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c964fd24e6166420d18fb53996d8c9fd6eac9bf5ae3ec3d03015be4414ce497f"}, + {file = "pydantic_core-2.33.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:681d65e9011f7392db5aa002b7423cc442d6a673c635668c227c6c8d0e5a4f77"}, + {file = "pydantic_core-2.33.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e100c52f7355a48413e2999bfb4e139d2977a904495441b374f3d4fb4a170961"}, + {file = "pydantic_core-2.33.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:048831bd363490be79acdd3232f74a0e9951b11b2b4cc058aeb72b22fdc3abe1"}, + {file = "pydantic_core-2.33.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bdc84017d28459c00db6f918a7272a5190bec3090058334e43a76afb279eac7c"}, + {file = "pydantic_core-2.33.1-cp311-cp311-win32.whl", hash = "sha256:32cd11c5914d1179df70406427097c7dcde19fddf1418c787540f4b730289896"}, + {file = "pydantic_core-2.33.1-cp311-cp311-win_amd64.whl", hash = "sha256:2ea62419ba8c397e7da28a9170a16219d310d2cf4970dbc65c32faf20d828c83"}, + {file = "pydantic_core-2.33.1-cp311-cp311-win_arm64.whl", hash = "sha256:fc903512177361e868bc1f5b80ac8c8a6e05fcdd574a5fb5ffeac5a9982b9e89"}, + {file = "pydantic_core-2.33.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1293d7febb995e9d3ec3ea09caf1a26214eec45b0f29f6074abb004723fc1de8"}, + {file = "pydantic_core-2.33.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:99b56acd433386c8f20be5c4000786d1e7ca0523c8eefc995d14d79c7a081498"}, + {file = "pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35a5ec3fa8c2fe6c53e1b2ccc2454398f95d5393ab398478f53e1afbbeb4d939"}, + {file = "pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b172f7b9d2f3abc0efd12e3386f7e48b576ef309544ac3a63e5e9cdd2e24585d"}, + {file = "pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9097b9f17f91eea659b9ec58148c0747ec354a42f7389b9d50701610d86f812e"}, + {file = "pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc77ec5b7e2118b152b0d886c7514a4653bcb58c6b1d760134a9fab915f777b3"}, + {file = "pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3d15245b08fa4a84cefc6c9222e6f37c98111c8679fbd94aa145f9a0ae23d"}, + {file = "pydantic_core-2.33.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef99779001d7ac2e2461d8ab55d3373fe7315caefdbecd8ced75304ae5a6fc6b"}, + {file = "pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:fc6bf8869e193855e8d91d91f6bf59699a5cdfaa47a404e278e776dd7f168b39"}, + {file = "pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:b1caa0bc2741b043db7823843e1bde8aaa58a55a58fda06083b0569f8b45693a"}, + {file = "pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ec259f62538e8bf364903a7d0d0239447059f9434b284f5536e8402b7dd198db"}, + {file = "pydantic_core-2.33.1-cp312-cp312-win32.whl", hash = "sha256:e14f369c98a7c15772b9da98987f58e2b509a93235582838bd0d1d8c08b68fda"}, + {file = "pydantic_core-2.33.1-cp312-cp312-win_amd64.whl", hash = "sha256:1c607801d85e2e123357b3893f82c97a42856192997b95b4d8325deb1cd0c5f4"}, + {file = "pydantic_core-2.33.1-cp312-cp312-win_arm64.whl", hash = "sha256:8d13f0276806ee722e70a1c93da19748594f19ac4299c7e41237fc791d1861ea"}, + {file = "pydantic_core-2.33.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:70af6a21237b53d1fe7b9325b20e65cbf2f0a848cf77bed492b029139701e66a"}, + {file = "pydantic_core-2.33.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:282b3fe1bbbe5ae35224a0dbd05aed9ccabccd241e8e6b60370484234b456266"}, + {file = "pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b315e596282bbb5822d0c7ee9d255595bd7506d1cb20c2911a4da0b970187d3"}, + {file = "pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1dfae24cf9921875ca0ca6a8ecb4bb2f13c855794ed0d468d6abbec6e6dcd44a"}, + {file = "pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6dd8ecfde08d8bfadaea669e83c63939af76f4cf5538a72597016edfa3fad516"}, + {file = "pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f593494876eae852dc98c43c6f260f45abdbfeec9e4324e31a481d948214764"}, + {file = "pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:948b73114f47fd7016088e5186d13faf5e1b2fe83f5e320e371f035557fd264d"}, + {file = "pydantic_core-2.33.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e11f3864eb516af21b01e25fac915a82e9ddad3bb0fb9e95a246067398b435a4"}, + {file = "pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:549150be302428b56fdad0c23c2741dcdb5572413776826c965619a25d9c6bde"}, + {file = "pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:495bc156026efafd9ef2d82372bd38afce78ddd82bf28ef5276c469e57c0c83e"}, + {file = "pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ec79de2a8680b1a67a07490bddf9636d5c2fab609ba8c57597e855fa5fa4dacd"}, + {file = "pydantic_core-2.33.1-cp313-cp313-win32.whl", hash = "sha256:ee12a7be1742f81b8a65b36c6921022301d466b82d80315d215c4c691724986f"}, + {file = "pydantic_core-2.33.1-cp313-cp313-win_amd64.whl", hash = "sha256:ede9b407e39949d2afc46385ce6bd6e11588660c26f80576c11c958e6647bc40"}, + {file = "pydantic_core-2.33.1-cp313-cp313-win_arm64.whl", hash = "sha256:aa687a23d4b7871a00e03ca96a09cad0f28f443690d300500603bd0adba4b523"}, + {file = "pydantic_core-2.33.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:401d7b76e1000d0dd5538e6381d28febdcacb097c8d340dde7d7fc6e13e9f95d"}, + {file = "pydantic_core-2.33.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7aeb055a42d734c0255c9e489ac67e75397d59c6fbe60d155851e9782f276a9c"}, + {file = "pydantic_core-2.33.1-cp313-cp313t-win_amd64.whl", hash = "sha256:338ea9b73e6e109f15ab439e62cb3b78aa752c7fd9536794112e14bee02c8d18"}, + {file = "pydantic_core-2.33.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:5ab77f45d33d264de66e1884fca158bc920cb5e27fd0764a72f72f5756ae8bdb"}, + {file = "pydantic_core-2.33.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7aaba1b4b03aaea7bb59e1b5856d734be011d3e6d98f5bcaa98cb30f375f2ad"}, + {file = "pydantic_core-2.33.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fb66263e9ba8fea2aa85e1e5578980d127fb37d7f2e292773e7bc3a38fb0c7b"}, + {file = "pydantic_core-2.33.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3f2648b9262607a7fb41d782cc263b48032ff7a03a835581abbf7a3bec62bcf5"}, + {file = "pydantic_core-2.33.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:723c5630c4259400818b4ad096735a829074601805d07f8cafc366d95786d331"}, + {file = "pydantic_core-2.33.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d100e3ae783d2167782391e0c1c7a20a31f55f8015f3293647544df3f9c67824"}, + {file = "pydantic_core-2.33.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177d50460bc976a0369920b6c744d927b0ecb8606fb56858ff542560251b19e5"}, + {file = "pydantic_core-2.33.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3edde68d1a1f9af1273b2fe798997b33f90308fb6d44d8550c89fc6a3647cf6"}, + {file = "pydantic_core-2.33.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a62c3c3ef6a7e2c45f7853b10b5bc4ddefd6ee3cd31024754a1a5842da7d598d"}, + {file = "pydantic_core-2.33.1-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:c91dbb0ab683fa0cd64a6e81907c8ff41d6497c346890e26b23de7ee55353f96"}, + {file = "pydantic_core-2.33.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9f466e8bf0a62dc43e068c12166281c2eca72121dd2adc1040f3aa1e21ef8599"}, + {file = "pydantic_core-2.33.1-cp39-cp39-win32.whl", hash = "sha256:ab0277cedb698749caada82e5d099dc9fed3f906a30d4c382d1a21725777a1e5"}, + {file = "pydantic_core-2.33.1-cp39-cp39-win_amd64.whl", hash = "sha256:5773da0ee2d17136b1f1c6fbde543398d452a6ad2a7b54ea1033e2daa739b8d2"}, + {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c834f54f8f4640fd7e4b193f80eb25a0602bba9e19b3cd2fc7ffe8199f5ae02"}, + {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:049e0de24cf23766f12cc5cc71d8abc07d4a9deb9061b334b62093dedc7cb068"}, + {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a28239037b3d6f16916a4c831a5a0eadf856bdd6d2e92c10a0da3a59eadcf3e"}, + {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d3da303ab5f378a268fa7d45f37d7d85c3ec19769f28d2cc0c61826a8de21fe"}, + {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:25626fb37b3c543818c14821afe0fd3830bc327a43953bc88db924b68c5723f1"}, + {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3ab2d36e20fbfcce8f02d73c33a8a7362980cff717926bbae030b93ae46b56c7"}, + {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:2f9284e11c751b003fd4215ad92d325d92c9cb19ee6729ebd87e3250072cdcde"}, + {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:048c01eee07d37cbd066fc512b9d8b5ea88ceeb4e629ab94b3e56965ad655add"}, + {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5ccd429694cf26af7997595d627dd2637e7932214486f55b8a357edaac9dae8c"}, + {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3a371dc00282c4b84246509a5ddc808e61b9864aa1eae9ecc92bb1268b82db4a"}, + {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f59295ecc75a1788af8ba92f2e8c6eeaa5a94c22fc4d151e8d9638814f85c8fc"}, + {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08530b8ac922003033f399128505f513e30ca770527cc8bbacf75a84fcc2c74b"}, + {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bae370459da6a5466978c0eacf90690cb57ec9d533f8e63e564ef3822bfa04fe"}, + {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e3de2777e3b9f4d603112f78006f4ae0acb936e95f06da6cb1a45fbad6bdb4b5"}, + {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3a64e81e8cba118e108d7126362ea30e021291b7805d47e4896e52c791be2761"}, + {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:52928d8c1b6bda03cc6d811e8923dffc87a2d3c8b3bfd2ce16471c7147a24850"}, + {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1b30d92c9412beb5ac6b10a3eb7ef92ccb14e3f2a8d7732e2d739f58b3aa7544"}, + {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f995719707e0e29f0f41a8aa3bcea6e761a36c9136104d3189eafb83f5cec5e5"}, + {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7edbc454a29fc6aeae1e1eecba4f07b63b8d76e76a748532233c4c167b4cb9ea"}, + {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ad05b683963f69a1d5d2c2bdab1274a31221ca737dbbceaa32bcb67359453cdd"}, + {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df6a94bf9452c6da9b5d76ed229a5683d0306ccb91cca8e1eea883189780d568"}, + {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7965c13b3967909a09ecc91f21d09cfc4576bf78140b988904e94f130f188396"}, + {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3f1fdb790440a34f6ecf7679e1863b825cb5ffde858a9197f851168ed08371e5"}, + {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:5277aec8d879f8d05168fdd17ae811dd313b8ff894aeeaf7cd34ad28b4d77e33"}, + {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8ab581d3530611897d863d1a649fb0644b860286b4718db919bfd51ece41f10b"}, + {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0483847fa9ad5e3412265c1bd72aad35235512d9ce9d27d81a56d935ef489672"}, + {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:de9e06abe3cc5ec6a2d5f75bc99b0bdca4f5c719a5b34026f8c57efbdecd2ee3"}, + {file = "pydantic_core-2.33.1.tar.gz", hash = "sha256:bcc9c6fdb0ced789245b02b7d6603e17d1563064ddcfc36f046b61c0c05dd9df"}, ] [package.dependencies] @@ -2263,13 +2261,13 @@ files = [ [[package]] name = "pydevd-pycharm" -version = "251.23774.37" +version = "251.23774.211" description = "PyCharm Debugger (used in PyCharm and PyDev)" optional = false python-versions = "*" groups = ["dev"] files = [ - {file = "pydevd_pycharm-251.23774.37.tar.gz", hash = "sha256:addbe1559edf1fcdf0aaf0bb66af6ae02bab0cd86447b296b477fe81a56b7909"}, + {file = "pydevd_pycharm-251.23774.211.tar.gz", hash = "sha256:82173214c3f4b12c6e738ccb7406cba312714a5ff46c76682d7880e338b3a9e5"}, ] [[package]] @@ -2485,29 +2483,29 @@ dev = ["backports.zoneinfo ; python_version < \"3.9\"", "black", "build", "freez [[package]] name = "pywin32" -version = "309" +version = "310" description = "Python for Window Extensions" optional = false python-versions = "*" groups = ["main"] markers = "platform_system == \"Windows\"" files = [ - {file = "pywin32-309-cp310-cp310-win32.whl", hash = "sha256:5b78d98550ca093a6fe7ab6d71733fbc886e2af9d4876d935e7f6e1cd6577ac9"}, - {file = "pywin32-309-cp310-cp310-win_amd64.whl", hash = "sha256:728d08046f3d65b90d4c77f71b6fbb551699e2005cc31bbffd1febd6a08aa698"}, - {file = "pywin32-309-cp310-cp310-win_arm64.whl", hash = "sha256:c667bcc0a1e6acaca8984eb3e2b6e42696fc035015f99ff8bc6c3db4c09a466a"}, - {file = "pywin32-309-cp311-cp311-win32.whl", hash = "sha256:d5df6faa32b868baf9ade7c9b25337fa5eced28eb1ab89082c8dae9c48e4cd51"}, - {file = "pywin32-309-cp311-cp311-win_amd64.whl", hash = "sha256:e7ec2cef6df0926f8a89fd64959eba591a1eeaf0258082065f7bdbe2121228db"}, - {file = "pywin32-309-cp311-cp311-win_arm64.whl", hash = "sha256:54ee296f6d11db1627216e9b4d4c3231856ed2d9f194c82f26c6cb5650163f4c"}, - {file = "pywin32-309-cp312-cp312-win32.whl", hash = "sha256:de9acacced5fa82f557298b1fed5fef7bd49beee04190f68e1e4783fbdc19926"}, - {file = "pywin32-309-cp312-cp312-win_amd64.whl", hash = "sha256:6ff9eebb77ffc3d59812c68db33c0a7817e1337e3537859499bd27586330fc9e"}, - {file = "pywin32-309-cp312-cp312-win_arm64.whl", hash = "sha256:619f3e0a327b5418d833f44dc87859523635cf339f86071cc65a13c07be3110f"}, - {file = "pywin32-309-cp313-cp313-win32.whl", hash = "sha256:008bffd4afd6de8ca46c6486085414cc898263a21a63c7f860d54c9d02b45c8d"}, - {file = "pywin32-309-cp313-cp313-win_amd64.whl", hash = "sha256:bd0724f58492db4cbfbeb1fcd606495205aa119370c0ddc4f70e5771a3ab768d"}, - {file = "pywin32-309-cp313-cp313-win_arm64.whl", hash = "sha256:8fd9669cfd41863b688a1bc9b1d4d2d76fd4ba2128be50a70b0ea66b8d37953b"}, - {file = "pywin32-309-cp38-cp38-win32.whl", hash = "sha256:617b837dc5d9dfa7e156dbfa7d3906c009a2881849a80a9ae7519f3dd8c6cb86"}, - {file = "pywin32-309-cp38-cp38-win_amd64.whl", hash = "sha256:0be3071f555480fbfd86a816a1a773880ee655bf186aa2931860dbb44e8424f8"}, - {file = "pywin32-309-cp39-cp39-win32.whl", hash = "sha256:72ae9ae3a7a6473223589a1621f9001fe802d59ed227fd6a8503c9af67c1d5f4"}, - {file = "pywin32-309-cp39-cp39-win_amd64.whl", hash = "sha256:88bc06d6a9feac70783de64089324568ecbc65866e2ab318eab35da3811fd7ef"}, + {file = "pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1"}, + {file = "pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d"}, + {file = "pywin32-310-cp310-cp310-win_arm64.whl", hash = "sha256:33babed0cf0c92a6f94cc6cc13546ab24ee13e3e800e61ed87609ab91e4c8213"}, + {file = "pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd"}, + {file = "pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c"}, + {file = "pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582"}, + {file = "pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d"}, + {file = "pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060"}, + {file = "pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966"}, + {file = "pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab"}, + {file = "pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e"}, + {file = "pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33"}, + {file = "pywin32-310-cp38-cp38-win32.whl", hash = "sha256:0867beb8addefa2e3979d4084352e4ac6e991ca45373390775f7084cc0209b9c"}, + {file = "pywin32-310-cp38-cp38-win_amd64.whl", hash = "sha256:30f0a9b3138fb5e07eb4973b7077e1883f558e40c578c6925acc7a94c34eaa36"}, + {file = "pywin32-310-cp39-cp39-win32.whl", hash = "sha256:851c8d927af0d879221e616ae1f66145253537bbdd321a77e8ef701b443a9a1a"}, + {file = "pywin32-310-cp39-cp39-win_amd64.whl", hash = "sha256:96867217335559ac619f00ad70e513c0fcf84b8a3af9fc2bba3b59b97da70475"}, ] [[package]] @@ -2575,14 +2573,14 @@ files = [ [[package]] name = "qrcode" -version = "8.0" +version = "8.1" description = "QR Code image generator" optional = false python-versions = "<4.0,>=3.9" groups = ["main"] files = [ - {file = "qrcode-8.0-py3-none-any.whl", hash = "sha256:9fc05f03305ad27a709eb742cf3097fa19e6f6f93bb9e2f039c0979190f6f1b1"}, - {file = "qrcode-8.0.tar.gz", hash = "sha256:025ce2b150f7fe4296d116ee9bad455a6643ab4f6e7dce541613a4758cbce347"}, + {file = "qrcode-8.1-py3-none-any.whl", hash = "sha256:9beba317d793ab8b3838c52af72e603b8ad2599c4e9bbd5c3da37c7dcc13c5cf"}, + {file = "qrcode-8.1.tar.gz", hash = "sha256:e8df73caf72c3bace3e93d9fa0af5aa78267d4f3f5bc7ab1b208f271605a5e48"}, ] [package.dependencies] @@ -2639,30 +2637,30 @@ test = ["hypothesis (>=6.22.0,<6.108.7)", "pytest (>=7.0.0)", "pytest-xdist (>=2 [[package]] name = "ruff" -version = "0.11.0" +version = "0.11.4" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.11.0-py3-none-linux_armv6l.whl", hash = "sha256:dc67e32bc3b29557513eb7eeabb23efdb25753684b913bebb8a0c62495095acb"}, - {file = "ruff-0.11.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:38c23fd9bdec4eb437b4c1e3595905a0a8edfccd63a790f818b28c78fe345639"}, - {file = "ruff-0.11.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7c8661b0be91a38bd56db593e9331beaf9064a79028adee2d5f392674bbc5e88"}, - {file = "ruff-0.11.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b6c0e8d3d2db7e9f6efd884f44b8dc542d5b6b590fc4bb334fdbc624d93a29a2"}, - {file = "ruff-0.11.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c3156d3f4b42e57247275a0a7e15a851c165a4fc89c5e8fa30ea6da4f7407b8"}, - {file = "ruff-0.11.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:490b1e147c1260545f6d041c4092483e3f6d8eba81dc2875eaebcf9140b53905"}, - {file = "ruff-0.11.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1bc09a7419e09662983b1312f6fa5dab829d6ab5d11f18c3760be7ca521c9329"}, - {file = "ruff-0.11.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcfa478daf61ac8002214eb2ca5f3e9365048506a9d52b11bea3ecea822bb844"}, - {file = "ruff-0.11.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6fbb2aed66fe742a6a3a0075ed467a459b7cedc5ae01008340075909d819df1e"}, - {file = "ruff-0.11.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92c0c1ff014351c0b0cdfdb1e35fa83b780f1e065667167bb9502d47ca41e6db"}, - {file = "ruff-0.11.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e4fd5ff5de5f83e0458a138e8a869c7c5e907541aec32b707f57cf9a5e124445"}, - {file = "ruff-0.11.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:96bc89a5c5fd21a04939773f9e0e276308be0935de06845110f43fd5c2e4ead7"}, - {file = "ruff-0.11.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a9352b9d767889ec5df1483f94870564e8102d4d7e99da52ebf564b882cdc2c7"}, - {file = "ruff-0.11.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:049a191969a10897fe052ef9cc7491b3ef6de79acd7790af7d7897b7a9bfbcb6"}, - {file = "ruff-0.11.0-py3-none-win32.whl", hash = "sha256:3191e9116b6b5bbe187447656f0c8526f0d36b6fd89ad78ccaad6bdc2fad7df2"}, - {file = "ruff-0.11.0-py3-none-win_amd64.whl", hash = "sha256:c58bfa00e740ca0a6c43d41fb004cd22d165302f360aaa56f7126d544db31a21"}, - {file = "ruff-0.11.0-py3-none-win_arm64.whl", hash = "sha256:868364fc23f5aa122b00c6f794211e85f7e78f5dffdf7c590ab90b8c4e69b657"}, - {file = "ruff-0.11.0.tar.gz", hash = "sha256:e55c620690a4a7ee6f1cccb256ec2157dc597d109400ae75bbf944fc9d6462e2"}, + {file = "ruff-0.11.4-py3-none-linux_armv6l.whl", hash = "sha256:d9f4a761ecbde448a2d3e12fb398647c7f0bf526dbc354a643ec505965824ed2"}, + {file = "ruff-0.11.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8c1747d903447d45ca3d40c794d1a56458c51e5cc1bc77b7b64bd2cf0b1626cc"}, + {file = "ruff-0.11.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:51a6494209cacca79e121e9b244dc30d3414dac8cc5afb93f852173a2ecfc906"}, + {file = "ruff-0.11.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f171605f65f4fc49c87f41b456e882cd0c89e4ac9d58e149a2b07930e1d466f"}, + {file = "ruff-0.11.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ebf99ea9af918878e6ce42098981fc8c1db3850fef2f1ada69fb1dcdb0f8e79e"}, + {file = "ruff-0.11.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edad2eac42279df12e176564a23fc6f4aaeeb09abba840627780b1bb11a9d223"}, + {file = "ruff-0.11.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f103a848be9ff379fc19b5d656c1f911d0a0b4e3e0424f9532ececf319a4296e"}, + {file = "ruff-0.11.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:193e6fac6eb60cc97b9f728e953c21cc38a20077ed64f912e9d62b97487f3f2d"}, + {file = "ruff-0.11.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7af4e5f69b7c138be8dcffa5b4a061bf6ba6a3301f632a6bce25d45daff9bc99"}, + {file = "ruff-0.11.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:126b1bf13154aa18ae2d6c3c5efe144ec14b97c60844cfa6eb960c2a05188222"}, + {file = "ruff-0.11.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8806daaf9dfa881a0ed603f8a0e364e4f11b6ed461b56cae2b1c0cab0645304"}, + {file = "ruff-0.11.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5d94bb1cc2fc94a769b0eb975344f1b1f3d294da1da9ddbb5a77665feb3a3019"}, + {file = "ruff-0.11.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:995071203d0fe2183fc7a268766fd7603afb9996785f086b0d76edee8755c896"}, + {file = "ruff-0.11.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7a37ca937e307ea18156e775a6ac6e02f34b99e8c23fe63c1996185a4efe0751"}, + {file = "ruff-0.11.4-py3-none-win32.whl", hash = "sha256:0e9365a7dff9b93af933dab8aebce53b72d8f815e131796268709890b4a83270"}, + {file = "ruff-0.11.4-py3-none-win_amd64.whl", hash = "sha256:5a9fa1c69c7815e39fcfb3646bbfd7f528fa8e2d4bebdcf4c2bd0fa037a255fb"}, + {file = "ruff-0.11.4-py3-none-win_arm64.whl", hash = "sha256:d435db6b9b93d02934cf61ef332e66af82da6d8c69aefdea5994c89997c7a0fc"}, + {file = "ruff-0.11.4.tar.gz", hash = "sha256:f45bd2fb1a56a5a85fae3b95add03fb185a0b30cf47f5edc92aa0355ca1d7407"}, ] [[package]] @@ -2708,26 +2706,41 @@ files = [ [[package]] name = "typing-extensions" -version = "4.12.2" +version = "4.13.1" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, - {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, + {file = "typing_extensions-4.13.1-py3-none-any.whl", hash = "sha256:4b6cf02909eb5495cfbc3f6e8fd49217e6cc7944e145cdda8caa3734777f9e69"}, + {file = "typing_extensions-4.13.1.tar.gz", hash = "sha256:98795af00fb9640edec5b8e31fc647597b4691f099ad75f469a2616be1a76dff"}, +] + +[[package]] +name = "typing-inspection" +version = "0.4.0" +description = "Runtime typing introspection tools" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f"}, + {file = "typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122"}, ] +[package.dependencies] +typing-extensions = ">=4.12.0" + [[package]] name = "typing-validation" -version = "1.2.11.post4" +version = "1.2.12" description = "A simple library for runtime type-checking." optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "typing_validation-1.2.11.post4-py3-none-any.whl", hash = "sha256:73dd504ddebf5210e80d5f65ba9b30efbd0fa42f266728fda7c4f0ba335c699c"}, - {file = "typing_validation-1.2.11.post4.tar.gz", hash = "sha256:7aed04ecfbda07e63b7266f90e5d096f96344f7facfe04bb081b21e4a9781670"}, + {file = "typing_validation-1.2.12-py3-none-any.whl", hash = "sha256:d68e22a41bf2b98ae91e5d6407db56e9ef83e9e5600164a7aff64aaa082fc232"}, + {file = "typing_validation-1.2.12.tar.gz", hash = "sha256:7ea9463a18bd04922e799cac1954f687e68e9564773f81db491536852ffe1d54"}, ] [package.extras] @@ -2816,14 +2829,14 @@ files = [ [[package]] name = "virtualenv" -version = "20.29.3" +version = "20.30.0" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "virtualenv-20.29.3-py3-none-any.whl", hash = "sha256:3e3d00f5807e83b234dfb6122bf37cfadf4be216c53a49ac059d02414f819170"}, - {file = "virtualenv-20.29.3.tar.gz", hash = "sha256:95e39403fcf3940ac45bc717597dba16110b74506131845d9b687d5e73d947ac"}, + {file = "virtualenv-20.30.0-py3-none-any.whl", hash = "sha256:e34302959180fca3af42d1800df014b35019490b119eba981af27f2fa486e5d6"}, + {file = "virtualenv-20.30.0.tar.gz", hash = "sha256:800863162bcaa5450a6e4d721049730e7f2dae07720e0902b0e4040bd6f9ada8"}, ] [package.dependencies] @@ -2833,7 +2846,7 @@ platformdirs = ">=3.9.1,<5" [package.extras] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"GraalVM\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] [[package]] name = "wcwidth" @@ -2871,100 +2884,105 @@ tests = ["pytest", "pytest-aiohttp (>=0.3.0)", "pytest-asyncio", "webargs[framew [[package]] name = "yarl" -version = "1.18.3" +version = "1.19.0" description = "Yet another URL library" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, - {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, - {file = "yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690"}, - {file = "yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6"}, - {file = "yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"}, - {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"}, - {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"}, - {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"}, - {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"}, - {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"}, - {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1"}, - {file = "yarl-1.18.3-cp39-cp39-win32.whl", hash = "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5"}, - {file = "yarl-1.18.3-cp39-cp39-win_amd64.whl", hash = "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9"}, - {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"}, - {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"}, + {file = "yarl-1.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0bae32f8ebd35c04d6528cedb4a26b8bf25339d3616b04613b97347f919b76d3"}, + {file = "yarl-1.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8015a076daf77823e7ebdcba474156587391dab4e70c732822960368c01251e6"}, + {file = "yarl-1.19.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9973ac95327f5d699eb620286c39365990b240031672b5c436a4cd00539596c5"}, + {file = "yarl-1.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd4b5fbd7b9dde785cfeb486b8cca211a0b138d4f3a7da27db89a25b3c482e5c"}, + {file = "yarl-1.19.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75460740005de5a912b19f657848aef419387426a40f581b1dc9fac0eb9addb5"}, + {file = "yarl-1.19.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:57abd66ca913f2cfbb51eb3dbbbac3648f1f6983f614a4446e0802e241441d2a"}, + {file = "yarl-1.19.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:46ade37911b7c99ce28a959147cb28bffbd14cea9e7dd91021e06a8d2359a5aa"}, + {file = "yarl-1.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8346ec72ada749a6b5d82bff7be72578eab056ad7ec38c04f668a685abde6af0"}, + {file = "yarl-1.19.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e4cb14a6ee5b6649ccf1c6d648b4da9220e8277d4d4380593c03cc08d8fe937"}, + {file = "yarl-1.19.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:66fc1c2926a73a2fb46e4b92e3a6c03904d9bc3a0b65e01cb7d2b84146a8bd3b"}, + {file = "yarl-1.19.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:5a70201dd1e0a4304849b6445a9891d7210604c27e67da59091d5412bc19e51c"}, + {file = "yarl-1.19.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e4807aab1bdeab6ae6f296be46337a260ae4b1f3a8c2fcd373e236b4b2b46efd"}, + {file = "yarl-1.19.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ae584afe81a1de4c1bb06672481050f0d001cad13163e3c019477409f638f9b7"}, + {file = "yarl-1.19.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:30eaf4459df6e91f21b2999d1ee18f891bcd51e3cbe1de301b4858c84385895b"}, + {file = "yarl-1.19.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0e617d45d03c8dec0dfce6f51f3e1b8a31aa81aaf4a4d1442fdb232bcf0c6d8c"}, + {file = "yarl-1.19.0-cp310-cp310-win32.whl", hash = "sha256:32ba32d0fa23893fd8ea8d05bdb05de6eb19d7f2106787024fd969f4ba5466cb"}, + {file = "yarl-1.19.0-cp310-cp310-win_amd64.whl", hash = "sha256:545575ecfcd465891b51546c2bcafdde0acd2c62c2097d8d71902050b20e4922"}, + {file = "yarl-1.19.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:163ff326680de5f6d4966954cf9e3fe1bf980f5fee2255e46e89b8cf0f3418b5"}, + {file = "yarl-1.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a626c4d9cca298d1be8625cff4b17004a9066330ac82d132bbda64a4c17c18d3"}, + {file = "yarl-1.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:961c3e401ea7f13d02b8bb7cb0c709152a632a6e14cdc8119e9c6ee5596cd45d"}, + {file = "yarl-1.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a39d7b807ab58e633ed760f80195cbd145b58ba265436af35f9080f1810dfe64"}, + {file = "yarl-1.19.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c4228978fb59c6b10f60124ba8e311c26151e176df364e996f3f8ff8b93971b5"}, + {file = "yarl-1.19.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9ba536b17ecf3c74a94239ec1137a3ad3caea8c0e4deb8c8d2ffe847d870a8c5"}, + {file = "yarl-1.19.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a251e00e445d2e9df7b827c9843c0b87f58a3254aaa3f162fb610747491fe00f"}, + {file = "yarl-1.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9b92431d8b4d4ca5ccbfdbac95b05a3a6cd70cd73aa62f32f9627acfde7549c"}, + {file = "yarl-1.19.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec2f56edaf476f70b5831bbd59700b53d9dd011b1f77cd4846b5ab5c5eafdb3f"}, + {file = "yarl-1.19.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:acf9b92c4245ac8b59bc7ec66a38d3dcb8d1f97fac934672529562bb824ecadb"}, + {file = "yarl-1.19.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:57711f1465c06fee8825b95c0b83e82991e6d9425f9a042c3c19070a70ac92bf"}, + {file = "yarl-1.19.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:528e86f5b1de0ad8dd758ddef4e0ed24f5d946d4a1cef80ffb2d4fca4e10f122"}, + {file = "yarl-1.19.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3b77173663e075d9e5a57e09d711e9da2f3266be729ecca0b8ae78190990d260"}, + {file = "yarl-1.19.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d8717924cf0a825b62b1a96fc7d28aab7f55a81bf5338b8ef41d7a76ab9223e9"}, + {file = "yarl-1.19.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0df9f0221a78d858793f40cbea3915c29f969c11366646a92ca47e080a14f881"}, + {file = "yarl-1.19.0-cp311-cp311-win32.whl", hash = "sha256:8b3ade62678ee2c7c10dcd6be19045135e9badad53108f7d2ed14896ee396045"}, + {file = "yarl-1.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:0626ee31edb23ac36bdffe607231de2cca055ad3a5e2dc5da587ef8bc6a321bc"}, + {file = "yarl-1.19.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:7b687c334da3ff8eab848c9620c47a253d005e78335e9ce0d6868ed7e8fd170b"}, + {file = "yarl-1.19.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b0fe766febcf523a2930b819c87bb92407ae1368662c1bc267234e79b20ff894"}, + {file = "yarl-1.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:742ceffd3c7beeb2b20d47cdb92c513eef83c9ef88c46829f88d5b06be6734ee"}, + {file = "yarl-1.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2af682a1e97437382ee0791eacbf540318bd487a942e068e7e0a6c571fadbbd3"}, + {file = "yarl-1.19.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:63702f1a098d0eaaea755e9c9d63172be1acb9e2d4aeb28b187092bcc9ca2d17"}, + {file = "yarl-1.19.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3560dcba3c71ae7382975dc1e912ee76e50b4cd7c34b454ed620d55464f11876"}, + {file = "yarl-1.19.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:68972df6a0cc47c8abaf77525a76ee5c5f6ea9bbdb79b9565b3234ded3c5e675"}, + {file = "yarl-1.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5684e7ff93ea74e47542232bd132f608df4d449f8968fde6b05aaf9e08a140f9"}, + {file = "yarl-1.19.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8182ad422bfacdebd4759ce3adc6055c0c79d4740aea1104e05652a81cd868c6"}, + {file = "yarl-1.19.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aee5b90a5a9b71ac57400a7bdd0feaa27c51e8f961decc8d412e720a004a1791"}, + {file = "yarl-1.19.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:8c0b2371858d5a814b08542d5d548adb03ff2d7ab32f23160e54e92250961a72"}, + {file = "yarl-1.19.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cd430c2b7df4ae92498da09e9b12cad5bdbb140d22d138f9e507de1aa3edfea3"}, + {file = "yarl-1.19.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a93208282c0ccdf73065fd76c6c129bd428dba5ff65d338ae7d2ab27169861a0"}, + {file = "yarl-1.19.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:b8179280cdeb4c36eb18d6534a328f9d40da60d2b96ac4a295c5f93e2799e9d9"}, + {file = "yarl-1.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eda3c2b42dc0c389b7cfda2c4df81c12eeb552019e0de28bde8f913fc3d1fcf3"}, + {file = "yarl-1.19.0-cp312-cp312-win32.whl", hash = "sha256:57f3fed859af367b9ca316ecc05ce79ce327d6466342734305aa5cc380e4d8be"}, + {file = "yarl-1.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:5507c1f7dd3d41251b67eecba331c8b2157cfd324849879bebf74676ce76aff7"}, + {file = "yarl-1.19.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:59281b9ed27bc410e0793833bcbe7fc149739d56ffa071d1e0fe70536a4f7b61"}, + {file = "yarl-1.19.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d27a6482ad5e05e8bafd47bf42866f8a1c0c3345abcb48d4511b3c29ecc197dc"}, + {file = "yarl-1.19.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7a8e19fd5a6fdf19a91f2409665c7a089ffe7b9b5394ab33c0eec04cbecdd01f"}, + {file = "yarl-1.19.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cda34ab19099c3a1685ad48fe45172536610c312b993310b5f1ca3eb83453b36"}, + {file = "yarl-1.19.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7908a25d33f94852b479910f9cae6cdb9e2a509894e8d5f416c8342c0253c397"}, + {file = "yarl-1.19.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e66c14d162bac94973e767b24de5d7e6c5153f7305a64ff4fcba701210bcd638"}, + {file = "yarl-1.19.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c03607bf932aa4cfae371e2dc9ca8b76faf031f106dac6a6ff1458418140c165"}, + {file = "yarl-1.19.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9931343d1c1f4e77421687b6b94bbebd8a15a64ab8279adf6fbb047eff47e536"}, + {file = "yarl-1.19.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:262087a8a0d73e1d169d45c2baf968126f93c97cf403e1af23a7d5455d52721f"}, + {file = "yarl-1.19.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:70f384921c24e703d249a6ccdabeb57dd6312b568b504c69e428a8dd3e8e68ca"}, + {file = "yarl-1.19.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:756b9ea5292a2c180d1fe782a377bc4159b3cfefaca7e41b5b0a00328ef62fa9"}, + {file = "yarl-1.19.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cbeb9c145d534c240a63b6ecc8a8dd451faeb67b3dc61d729ec197bb93e29497"}, + {file = "yarl-1.19.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:087ae8f8319848c18e0d114d0f56131a9c017f29200ab1413b0137ad7c83e2ae"}, + {file = "yarl-1.19.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362f5480ba527b6c26ff58cff1f229afe8b7fdd54ee5ffac2ab827c1a75fc71c"}, + {file = "yarl-1.19.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f408d4b4315e814e5c3668094e33d885f13c7809cbe831cbdc5b1bb8c7a448f4"}, + {file = "yarl-1.19.0-cp313-cp313-win32.whl", hash = "sha256:24e4c367ad69988a2283dd45ea88172561ca24b2326b9781e164eb46eea68345"}, + {file = "yarl-1.19.0-cp313-cp313-win_amd64.whl", hash = "sha256:0110f91c57ab43d1538dfa92d61c45e33b84df9257bd08fcfcda90cce931cbc9"}, + {file = "yarl-1.19.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:85ac908cd5a97bbd3048cca9f1bf37b932ea26c3885099444f34b0bf5d5e9fa6"}, + {file = "yarl-1.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6ba0931b559f1345df48a78521c31cfe356585670e8be22af84a33a39f7b9221"}, + {file = "yarl-1.19.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5bc503e1c1fee1b86bcb58db67c032957a52cae39fe8ddd95441f414ffbab83e"}, + {file = "yarl-1.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d995122dcaf180fd4830a9aa425abddab7c0246107c21ecca2fa085611fa7ce9"}, + {file = "yarl-1.19.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:217f69e60a14da4eed454a030ea8283f8fbd01a7d6d81e57efb865856822489b"}, + {file = "yarl-1.19.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aad67c8f13a4b79990082f72ef09c078a77de2b39899aabf3960a48069704973"}, + {file = "yarl-1.19.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dff065a1a8ed051d7e641369ba1ad030d5a707afac54cf4ede7069b959898835"}, + {file = "yarl-1.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ada882e26b16ee651ab6544ce956f2f4beaed38261238f67c2a96db748e17741"}, + {file = "yarl-1.19.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67a56b1acc7093451ea2de0687aa3bd4e58d6b4ef6cbeeaad137b45203deaade"}, + {file = "yarl-1.19.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e97d2f0a06b39e231e59ebab0e6eec45c7683b339e8262299ac952707bdf7688"}, + {file = "yarl-1.19.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:a5288adb7c59d0f54e4ad58d86fb06d4b26e08a59ed06d00a1aac978c0e32884"}, + {file = "yarl-1.19.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1efbf4d03e6eddf5da27752e0b67a8e70599053436e9344d0969532baa99df53"}, + {file = "yarl-1.19.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:f228f42f29cc87db67020f7d71624102b2c837686e55317b16e1d3ef2747a993"}, + {file = "yarl-1.19.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c515f7dd60ca724e4c62b34aeaa603188964abed2eb66bb8e220f7f104d5a187"}, + {file = "yarl-1.19.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4815ec6d3d68a96557fa71bd36661b45ac773fb50e5cfa31a7e843edb098f060"}, + {file = "yarl-1.19.0-cp39-cp39-win32.whl", hash = "sha256:9fac2dd1c5ecb921359d9546bc23a6dcc18c6acd50c6d96f118188d68010f497"}, + {file = "yarl-1.19.0-cp39-cp39-win_amd64.whl", hash = "sha256:5864f539ce86b935053bfa18205fa08ce38e9a40ea4d51b19ce923345f0ed5db"}, + {file = "yarl-1.19.0-py3-none-any.whl", hash = "sha256:a727101eb27f66727576630d02985d8a065d09cd0b5fcbe38a5793f71b2a97ef"}, + {file = "yarl-1.19.0.tar.gz", hash = "sha256:01e02bb80ae0dbed44273c304095295106e1d9470460e773268a27d11e594892"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" -propcache = ">=0.2.0" +propcache = ">=0.2.1" [extras] bbs = ["ursa-bbs-signatures"] @@ -2973,4 +2991,4 @@ didcommv2 = ["didcomm-messaging"] [metadata] lock-version = "2.1" python-versions = "^3.12" -content-hash = "1a902795ad6eb2188cd8e1d5a804524edbb895f3d7abe5fd39fe4a42d7331d7b" +content-hash = "08cd1d128c971c745a84bc0cb1c9698b80a37e5f444fe7c2d7e301a14dbaabaa" diff --git a/pyproject.toml b/pyproject.toml index aed53dca86..ffc7a6f9b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ repository = "https://github.com/openwallet-foundation/acapy" [tool.poetry.dependencies] python = "^3.12" -aiohttp = "~3.11.12" +aiohttp = "~3.11.16" aiohttp-apispec-acapy = "~3.0.3" aiohttp-cors = ">=0.7,<0.9" apispec = "^6.6.0" @@ -39,7 +39,7 @@ pynacl = "~1.5.0" python-dateutil = "^2.9.0" python-json-logger = "^3.2.1" pyyaml = "~6.0.2" -qrcode = { version = "^8.0", extras = ["pil"] } +qrcode = { version = "^8.1", extras = ["pil"] } requests = "~2.32.3" rlp = "^4.1.0" unflatten = "~0.2" @@ -70,7 +70,7 @@ canonicaljson = "^2.0.0" [tool.poetry.group.dev.dependencies] # Sync with version in .pre-commit-config.yaml and .github/workflows/format.yml -ruff = "~0.11.0" +ruff = "~0.11.4" pre-commit = ">=4.1,<4.3" From 38c14744c0fbcda55534fb81b697fb45e12aa2d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 11:35:19 +0000 Subject: [PATCH 69/76] chore(deps): Update qrcode[pil] requirement from ~=8.0 to ~=8.1 (#3632) --- demo/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/requirements.txt b/demo/requirements.txt index 64c93ba07b..ad895462cf 100644 --- a/demo/requirements.txt +++ b/demo/requirements.txt @@ -2,4 +2,4 @@ asyncpg~=0.30.0 prompt_toolkit~=2.0.10 web.py~=0.62 pygments~=2.19 -qrcode[pil]~=8.0 +qrcode[pil]~=8.1 From 8a3a3fa10dbd8866007dc6a49591f918e540da04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emiliano=20Sun=CC=83e=CC=81?= Date: Fri, 4 Apr 2025 21:40:28 +0000 Subject: [PATCH 70/76] Use current version of aca-py in devcontainer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Emiliano Suñé --- .devcontainer/post-install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/post-install.sh b/.devcontainer/post-install.sh index 0edc96fe5a..d9a8bef742 100644 --- a/.devcontainer/post-install.sh +++ b/.devcontainer/post-install.sh @@ -8,8 +8,8 @@ WORKSPACE_DIR=$(pwd) python -m pip install --upgrade pip pip3 install -r demo/requirements.txt -r demo/requirements.behave.txt -# install a version of acapy-agent so the pytests can pick up a version -pip3 install acapy-agent +# install current version of acapy-agent so the pytests can pick up a version +pip3 install . # hack/workaround to allow `pytest .` and `poetry run pytest` work. # need to not run ruff... From 38f3af809ca69342d68ef72caa97451d01d5910c Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Wed, 9 Apr 2025 11:26:11 +0200 Subject: [PATCH 71/76] :sparkles: Don't shutdown on ledger error (#3636) * :sparkles: Don't shutdown on ledger error Signed-off-by: ff137 * :white_check_mark: Fix tests Signed-off-by: ff137 * :test_tube: Don't skip test Signed-off-by: ff137 * :test_tube: Cover StorageNotFoundError scenario Signed-off-by: ff137 * :test_tube: Fix confusing unawaited coroutine warning Signed-off-by: ff137 --------- Signed-off-by: ff137 Co-authored-by: Stephen Curran --- acapy_agent/core/conductor.py | 46 ++++++++++++------------ acapy_agent/core/tests/test_conductor.py | 44 ++++++----------------- 2 files changed, 33 insertions(+), 57 deletions(-) diff --git a/acapy_agent/core/conductor.py b/acapy_agent/core/conductor.py index eea46cd716..3459f32d8e 100644 --- a/acapy_agent/core/conductor.py +++ b/acapy_agent/core/conductor.py @@ -74,7 +74,7 @@ from ..wallet.anoncreds_upgrade import upgrade_wallet_to_anoncreds_if_requested from ..wallet.did_info import DIDInfo from .dispatcher import Dispatcher -from .error import StartupError +from .error import ProfileError, StartupError from .oob_processor import OobMessageProcessor from .util import SHUTDOWN_EVENT_TOPIC, STARTUP_EVENT_TOPIC @@ -559,31 +559,31 @@ def inbound_message_router( lambda completed: self.dispatch_complete(message, completed), ) except (LedgerConfigError, LedgerTransactionError) as e: - LOGGER.error("Shutdown on ledger error %s", str(e)) - if self.admin_server: - self.admin_server.notify_fatal_error() + LOGGER.error("Ledger error occurred in message handler: %s", str(e)) raise def dispatch_complete(self, message: InboundMessage, completed: CompletedTask): """Handle completion of message dispatch.""" if completed.exc_info: - LOGGER.exception("Exception in message handler:", exc_info=completed.exc_info) - if isinstance(completed.exc_info[1], LedgerConfigError) or isinstance( - completed.exc_info[1], LedgerTransactionError - ): + exc_class, exc, _ = completed.exc_info + if isinstance(exc, (LedgerConfigError, LedgerTransactionError)): LOGGER.error( - "%shutdown on ledger error %s", - "S" if self.admin_server else "No admin server to s", - str(completed.exc_info[1]), + "Ledger error occurred in message handler: %s", + str(exc), + exc_info=completed.exc_info, ) - if self.admin_server: - self.admin_server.notify_fatal_error() - else: + elif isinstance(exc, (ProfileError, StorageNotFoundError)): LOGGER.error( - "DON'T shutdown on %s %s", - completed.exc_info[0].__name__, - str(completed.exc_info[1]), + "Storage error occurred in message handler: %s: %s", + exc_class.__name__, + str(exc), + exc_info=completed.exc_info, + ) + else: + LOGGER.exception( + "Exception in message handler:", exc_info=completed.exc_info ) + self.inbound_transport_manager.dispatch_complete(message, completed) async def get_stats(self) -> dict: @@ -656,9 +656,9 @@ def handle_not_returned(self, profile: Profile, outbound: OutboundMessage): try: self.dispatcher.run_task(self.queue_outbound(profile, outbound)) except (LedgerConfigError, LedgerTransactionError) as e: - LOGGER.error("Shutdown on ledger error %s", str(e)) - if self.admin_server: - self.admin_server.notify_fatal_error() + LOGGER.error( + "Ledger error occurred while handling failed delivery: %s", str(e) + ) raise async def queue_outbound( @@ -688,9 +688,9 @@ async def queue_outbound( LOGGER.exception("Error preparing outbound message for transmission") return OutboundSendStatus.UNDELIVERABLE except (LedgerConfigError, LedgerTransactionError) as e: - LOGGER.error("Shutdown on ledger error %s", str(e)) - if self.admin_server: - self.admin_server.notify_fatal_error() + LOGGER.error( + "Ledger error occurred while preparing outbound message: %s", str(e) + ) raise del conn_mgr # Find oob/connectionless target we can send the message to diff --git a/acapy_agent/core/tests/test_conductor.py b/acapy_agent/core/tests/test_conductor.py index 042cd1974d..153e83562f 100644 --- a/acapy_agent/core/tests/test_conductor.py +++ b/acapy_agent/core/tests/test_conductor.py @@ -1,12 +1,10 @@ from unittest import IsolatedAsyncioTestCase -import pytest - -from ...connections.base_manager import BaseConnectionManager from ...admin.base_server import BaseAdminServer from ...askar.profile import AskarProfileManager from ...config.base_context import ContextBuilder from ...config.injection_context import InjectionContext +from ...connections.base_manager import BaseConnectionManager from ...connections.models.conn_record import ConnRecord from ...connections.models.connection_target import ConnectionTarget from ...connections.models.diddoc import DIDDoc, PublicKey, PublicKeyType, Service @@ -587,9 +585,7 @@ async def test_inbound_message_handler_ledger_x(self): mock.patch.object( conductor.dispatcher, "queue_message", autospec=True ) as mock_dispatch_q, - mock.patch.object( - conductor.admin_server, "notify_fatal_error", mock.MagicMock() - ) as mock_notify, + mock.patch.object(test_module, "LOGGER", mock.MagicMock()) as mock_logger, ): mock_dispatch_q.side_effect = test_module.LedgerConfigError("ledger down") @@ -603,7 +599,7 @@ async def test_inbound_message_handler_ledger_x(self): ) mock_dispatch_q.assert_called_once() - mock_notify.assert_called_once() + mock_logger.error.assert_called_once() async def test_outbound_message_handler_return_route(self): builder: ContextBuilder = StubContextBuilder(self.test_settings) @@ -830,18 +826,10 @@ async def test_handle_nots(self): conductor.dispatcher, "run_task", mock.MagicMock() ) as mock_run_task, ): - # Normally this should be a coroutine mock; however, the coroutine - # is awaited by dispatcher.run_task, which is mocked here. MagicMock - # to prevent unawaited coroutine warning. - mock_conn_mgr.return_value.get_connection_targets = mock.MagicMock() mock_run_task.side_effect = test_module.BaseConnectionManagerError() await conductor.queue_outbound(conductor.root_profile, message) - mock_outbound_mgr.return_value.enqueue_message.assert_not_called() message.connection_id = None - mock_outbound_mgr.return_value.enqueue_message.side_effect = ( - test_module.OutboundDeliveryError() - ) await conductor.queue_outbound(conductor.root_profile, message) mock_run_task.assert_called_once() @@ -870,7 +858,6 @@ async def test_handle_outbound_queue(self): await conductor.queue_outbound(conductor.root_profile, message) - @pytest.mark.skip("This test has a bad mock that isn't awaited") async def test_handle_not_returned_ledger_x(self): builder: ContextBuilder = StubContextBuilder(self.test_settings_admin) conductor = test_module.Conductor(builder) @@ -898,9 +885,7 @@ async def test_handle_not_returned_ledger_x(self): mock.patch.object( conductor.dispatcher, "run_task", mock.MagicMock() ) as mock_dispatch_run, - mock.patch.object( - conductor.admin_server, "notify_fatal_error", mock.MagicMock() - ) as mock_notify, + mock.patch.object(conductor, "queue_outbound", mock.MagicMock()), ): mock_dispatch_run.side_effect = test_module.LedgerConfigError( "No such ledger" @@ -917,7 +902,6 @@ async def test_handle_not_returned_ledger_x(self): conductor.handle_not_returned(conductor.root_profile, message) mock_dispatch_run.assert_called_once() - mock_notify.assert_called_once() async def test_queue_outbound_ledger_x(self): builder: ContextBuilder = StubContextBuilder(self.test_settings_admin) @@ -949,14 +933,8 @@ async def test_queue_outbound_ledger_x(self): mock.patch.object( conductor.dispatcher, "run_task", mock.MagicMock() ) as mock_dispatch_run, - mock.patch.object( - conductor.admin_server, "notify_fatal_error", mock.MagicMock() - ) as mock_notify, + mock.patch.object(test_module, "LOGGER", mock.MagicMock()) as mock_logger, ): - # Normally this should be a coroutine mock; however, the coroutine - # is awaited by dispatcher.run_task, which is mocked here. MagicMock - # to prevent unawaited coroutine warning. - conn_mgr.get_connection_targets = mock.MagicMock() mock_dispatch_run.side_effect = test_module.LedgerConfigError( "No such ledger" ) @@ -972,7 +950,7 @@ async def test_queue_outbound_ledger_x(self): await conductor.queue_outbound(conductor.root_profile, message) mock_dispatch_run.assert_called_once() - mock_notify.assert_called_once() + mock_logger.error.assert_called_once() async def test_admin(self): builder: ContextBuilder = StubContextBuilder(self.test_settings) @@ -1217,7 +1195,7 @@ async def test_dispatch_complete_non_fatal_x(self): message_body = "{}" receipt = MessageReceipt(direct_response_mode="snail mail") message = InboundMessage(message_body, receipt) - exc = KeyError("sample exception") + exc = StorageNotFoundError("sample exception") mock_task = mock.MagicMock( exc_info=(type(exc), exc, exc.__traceback__), ident="abc", @@ -1255,7 +1233,7 @@ async def test_dispatch_complete_non_fatal_x(self): conductor.dispatch_complete(message, mock_task) mock_notify.assert_not_called() - async def test_dispatch_complete_fatal_x(self): + async def test_dispatch_complete_ledger_error_x(self): builder: ContextBuilder = StubContextBuilder(self.test_settings_admin) conductor = test_module.Conductor(builder) @@ -1294,11 +1272,9 @@ async def test_dispatch_complete_fatal_x(self): } await conductor.setup() - with mock.patch.object( - conductor.admin_server, "notify_fatal_error", mock.MagicMock() - ) as mock_notify: + with mock.patch.object(test_module, "LOGGER", mock.MagicMock()) as mock_logger: conductor.dispatch_complete(message, mock_task) - mock_notify.assert_called_once_with() + mock_logger.error.assert_called_once() async def test_clear_default_mediator(self): builder: ContextBuilder = StubContextBuilder(self.test_settings) From abc31d3ad059ace0ad7a8a36e155f76fbf5e811e Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Wed, 9 Apr 2025 16:54:22 +0200 Subject: [PATCH 72/76] :sparkles: Improve logging in core components (#3332) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :art: Refactor `register_plugin` steps for maintainability Signed-off-by: ff137 * :art: improve logging in register_package Signed-off-by: ff137 * :art: Rename method and remove redundant main call Signed-off-by: ff137 * :art: Signed-off-by: ff137 * :loud_sound: Add debug logging to Context Builder Signed-off-by: ff137 * :art: Deduplicate registering list of plugins Signed-off-by: ff137 * :art: Signed-off-by: ff137 * :loud_sound: Add debug logging to init_context Signed-off-by: ff137 * :loud_sound: Add debug logging to load_protocol_version Signed-off-by: ff137 * :loud_sound: Add debug logging to load_protocols Signed-off-by: ff137 * :loud_sound: Add debug logging to register_admin_routes Signed-off-by: ff137 * :loud_sound: Add debug logging to register_protocol_events Signed-off-by: ff137 * :loud_sound: Add debug logging to post_process_routes Signed-off-by: ff137 * :art: Replace print statements with info logs Signed-off-by: ff137 * :art: Replace almost all print statements with info logs Signed-off-by: ff137 * :loud_sound: Expand logging for Conductor setup Signed-off-by: ff137 * :art: Correct to uphold previous "Module doesn't exist" log behaviour Signed-off-by: ff137 * Revert ":art: Rename method and remove redundant main call" This reverts commit 2f6526d108b3a8df527d2694c9ce3c46e438f963. Signed-off-by: ff137 * :art: Signed-off-by: ff137 * :white_check_mark: Fix test by adding __name__ to mock object Signed-off-by: ff137 * :art: Signed-off-by: ff137 * :sparkles: Add custom trace log level Signed-off-by: ff137 * :art: Ensure trace level can only be added once Signed-off-by: ff137 * :art: Add Logger Signed-off-by: ff137 * :art: Update newly added logs to be trace level instead of debug Signed-off-by: ff137 * :art: Update newly added logs to be trace level instead of debug Signed-off-by: ff137 * :loud_sound: Expand logging for Conductor start and stop Signed-off-by: ff137 * :white_check_mark: Add unit tests for adding trace level functionality Signed-off-by: ff137 * :white_check_mark: Reset the logging states before and after TestLoggingUtils is run Signed-off-by: ff137 * :art: Signed-off-by: ff137 * :art: Signed-off-by: ff137 * :bug: Handle case that load_module return type is Optional Signed-off-by: ff137 * :loud_sound: Expand logging for ClassLoader Signed-off-by: ff137 * :loud_sound: Log a warning if resource not found, instead of passing Signed-off-by: ff137 * :art: Signed-off-by: ff137 * :art: Enable trace logs for remaining modules Signed-off-by: ff137 * :bug: Fix registering and loading of modules Signed-off-by: ff137 * :loud_sound: Expand logging for Ledger Configuration Signed-off-by: ff137 * :rewind: Revert `trace` log changes, and move to debug level Signed-off-by: ff137 * :sparkles: Add caching to ClassLoader.load_module Signed-off-by: ff137 * :art: Improve log Signed-off-by: ff137 * :art: Reduce log verbosity Signed-off-by: ff137 * :sparkles: Add `lru_cache` to load_class and set maxsize Signed-off-by: ff137 * :rewind: Revert addition of lru caching Signed-off-by: ff137 * :art: Update logs / reduce verbosity Signed-off-by: ff137 * :art: Reduce repetition Signed-off-by: ff137 * :art: Log warning when StorageNotFoundError encountered, instead of exception stacktrace Signed-off-by: ff137 * :art: Set Shutdown log level to fatal, with exc_info Signed-off-by: ff137 * :art: Log warning for bad credential format, instead of always exception stacktrace Signed-off-by: ff137 * :construction: Add exc_info to error log for debugging Signed-off-by: ff137 * :art: Replace AskarError with ProfileError Signed-off-by: ff137 * 🔊 Reduce noisy debug logs Signed-off-by: ff137 * :art: Re-add some worthwhile comments Signed-off-by: ff137 * :art: Still log "Incoming request" for status checks Signed-off-by: ff137 --------- Signed-off-by: ff137 Co-authored-by: Stephen Curran --- acapy_agent/__main__.py | 13 +- acapy_agent/admin/server.py | 13 +- .../anoncreds/default/did_indy/registry.py | 2 +- .../anoncreds/default/did_web/registry.py | 5 +- .../anoncreds/default/legacy_indy/registry.py | 2 +- acapy_agent/commands/provision.py | 7 +- acapy_agent/commands/start.py | 4 +- acapy_agent/config/argparse.py | 2 +- acapy_agent/config/default_context.py | 12 +- acapy_agent/config/ledger.py | 30 +- acapy_agent/config/logging/configurator.py | 18 +- acapy_agent/core/conductor.py | 173 +++++++--- acapy_agent/core/dispatcher.py | 7 +- acapy_agent/core/plugin_registry.py | 295 +++++++++++------- .../core/tests/test_plugin_registry.py | 2 + .../handlers/cred_problem_report_handler.py | 8 +- .../protocols/issue_credential/v2_0/routes.py | 7 +- .../handlers/pres_problem_report_handler.py | 8 +- acapy_agent/transport/v2_pack_format.py | 3 +- acapy_agent/utils/classloader.py | 42 ++- acapy_agent/vc/vc_di/prove.py | 5 +- acapy_agent/wallet/crypto.py | 5 +- 22 files changed, 460 insertions(+), 203 deletions(-) diff --git a/acapy_agent/__main__.py b/acapy_agent/__main__.py index bd0c964705..9669588b83 100644 --- a/acapy_agent/__main__.py +++ b/acapy_agent/__main__.py @@ -1,8 +1,11 @@ """acapy_agent package entry point.""" +import logging import os import sys +LOGGER = logging.getLogger(__name__) + def init_debug(args): """Initialize debugging environment.""" @@ -26,16 +29,18 @@ def init_debug(args): import debugpy debugpy.listen((DAP_HOST, DAP_PORT)) - print(f"=== Waiting for debugger to attach to {DAP_HOST}:{DAP_PORT} ===") + LOGGER.info( + f"=== Waiting for debugger to attach to {DAP_HOST}:{DAP_PORT} ===" + ) debugpy.wait_for_client() except ImportError: - print("debugpy library was not found") + LOGGER.error("debugpy library was not found") if ENABLE_PYDEVD_PYCHARM or "--debug-pycharm" in args: try: import pydevd_pycharm - print( + LOGGER.info( "aca-py remote debugging to " f"{PYDEVD_PYCHARM_HOST}:{PYDEVD_PYCHARM_AGENT_PORT}" ) @@ -47,7 +52,7 @@ def init_debug(args): suspend=False, ) except ImportError: - print("pydevd_pycharm library was not found") + LOGGER.error("pydevd_pycharm library was not found") def run(args): diff --git a/acapy_agent/admin/server.py b/acapy_agent/admin/server.py index c526e75435..fa32df503f 100644 --- a/acapy_agent/admin/server.py +++ b/acapy_agent/admin/server.py @@ -226,11 +226,14 @@ async def upgrade_middleware(request: web.BaseRequest, handler: Coroutine): async def debug_middleware(request: web.BaseRequest, handler: Coroutine): """Show request detail in debug log.""" - if LOGGER.isEnabledFor(logging.DEBUG): - LOGGER.debug(f"Incoming request: {request.method} {request.path_qs}") - LOGGER.debug(f"Match info: {request.match_info}") - body = await request.text() if request.body_exists else None - LOGGER.debug(f"Body: {body}") + if LOGGER.isEnabledFor(logging.DEBUG): # Skipped if DEBUG is not enabled + LOGGER.debug("Incoming request: %s %s", request.method, request.path_qs) + is_status_check = str(request.rel_url).startswith("/status/") + if not is_status_check: # Don't log match info for status checks; reduces noise + LOGGER.debug("Match info: %s", request.match_info) + + if request.body_exists: # Only log body if it exists + LOGGER.debug("Body: %s", await request.text()) return await handler(request) diff --git a/acapy_agent/anoncreds/default/did_indy/registry.py b/acapy_agent/anoncreds/default/did_indy/registry.py index 6bd6cae693..0234196571 100644 --- a/acapy_agent/anoncreds/default/did_indy/registry.py +++ b/acapy_agent/anoncreds/default/did_indy/registry.py @@ -42,7 +42,7 @@ def supported_identifiers_regex(self) -> Pattern: async def setup(self, context: InjectionContext): """Setup.""" - print("Successfully registered DIDIndyRegistry") + LOGGER.info("Successfully registered DIDIndyRegistry") async def get_schema(self, profile: Profile, schema_id: str) -> GetSchemaResult: """Get a schema from the registry.""" diff --git a/acapy_agent/anoncreds/default/did_web/registry.py b/acapy_agent/anoncreds/default/did_web/registry.py index c53ed2c4cd..3f2535cc7a 100644 --- a/acapy_agent/anoncreds/default/did_web/registry.py +++ b/acapy_agent/anoncreds/default/did_web/registry.py @@ -1,5 +1,6 @@ """DID Web Registry.""" +import logging import re from typing import Optional, Pattern, Sequence @@ -18,6 +19,8 @@ from ...models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult from ...models.schema_info import AnoncredsSchemaInfo +LOGGER = logging.getLogger(__name__) + class DIDWebRegistry(BaseAnonCredsResolver, BaseAnonCredsRegistrar): """DIDWebRegistry.""" @@ -41,7 +44,7 @@ def supported_identifiers_regex(self) -> Pattern: async def setup(self, context: InjectionContext): """Setup.""" - print("Successfully registered DIDWebRegistry") + LOGGER.info("Successfully registered DIDWebRegistry") async def get_schema(self, profile, schema_id: str) -> GetSchemaResult: """Get a schema from the registry.""" diff --git a/acapy_agent/anoncreds/default/legacy_indy/registry.py b/acapy_agent/anoncreds/default/legacy_indy/registry.py index aad288d053..950ce434a6 100644 --- a/acapy_agent/anoncreds/default/legacy_indy/registry.py +++ b/acapy_agent/anoncreds/default/legacy_indy/registry.py @@ -145,7 +145,7 @@ def supported_identifiers_regex(self) -> Pattern: async def setup(self, context: InjectionContext): """Setup.""" - print("Successfully registered LegacyIndyRegistry") + LOGGER.info("Successfully registered LegacyIndyRegistry") @staticmethod def make_schema_id(schema: AnonCredsSchema) -> str: diff --git a/acapy_agent/commands/provision.py b/acapy_agent/commands/provision.py index 962b38dc8e..f0fb7cf561 100644 --- a/acapy_agent/commands/provision.py +++ b/acapy_agent/commands/provision.py @@ -1,6 +1,7 @@ """Provision command for setting up agent settings before starting.""" import asyncio +import logging from typing import Sequence from configargparse import ArgumentParser @@ -22,6 +23,8 @@ from ..storage.base import BaseStorage from . import PROG +LOGGER = logging.getLogger(__name__) + class ProvisionError(BaseError): """Base exception for provisioning errors.""" @@ -58,9 +61,9 @@ async def provision(settings: dict): ) if await ledger_config(root_profile, public_did and public_did.did, True): - print("Ledger configured") + LOGGER.info("Ledger configured") else: - print("Ledger not configured") + LOGGER.warning("Ledger not configured") await root_profile.close() except BaseError as e: diff --git a/acapy_agent/commands/start.py b/acapy_agent/commands/start.py index f30fc5c582..fb8652314c 100644 --- a/acapy_agent/commands/start.py +++ b/acapy_agent/commands/start.py @@ -31,7 +31,7 @@ async def start_app(conductor: Conductor): async def shutdown_app(conductor: Conductor): """Shut down.""" - print("\nShutting down") + LOGGER.info("Shutting down") await conductor.stop() @@ -59,7 +59,7 @@ def execute(argv: Sequence[str] = None): # Run the application if uvloop: uvloop.install() - print("uvloop installed") + LOGGER.info("uvloop installed") run_loop(start_app(conductor), shutdown_app(conductor)) diff --git a/acapy_agent/config/argparse.py b/acapy_agent/config/argparse.py index f667aec4d4..86f5b9cb1c 100644 --- a/acapy_agent/config/argparse.py +++ b/acapy_agent/config/argparse.py @@ -63,7 +63,7 @@ def get_registered(cls, category: Optional[str] = None): def create_argument_parser(*, prog: Optional[str] = None): - """Create am instance of an arg parser, force yaml format for external config.""" + """Create an instance of an arg parser, force yaml format for external config.""" return ArgumentParser(config_file_parser_class=YAMLConfigFileParser, prog=prog) diff --git a/acapy_agent/config/default_context.py b/acapy_agent/config/default_context.py index 9b1c99d0f7..2a22547eec 100644 --- a/acapy_agent/config/default_context.py +++ b/acapy_agent/config/default_context.py @@ -36,11 +36,14 @@ class DefaultContextBuilder(ContextBuilder): async def build_context(self) -> InjectionContext: """Build the base injection context; set DIDComm prefix to emit.""" + LOGGER.debug("Building new injection context") + context = InjectionContext(settings=self.settings) context.settings.set_default("default_label", "Aries Cloud Agent") if context.settings.get("timing.enabled"): timing_log = context.settings.get("timing.log_file") + LOGGER.debug("Enabling timing collector with log file: %s", timing_log) collector = Collector(log_path=timing_log) context.injector.bind_instance(Collector, collector) @@ -67,6 +70,7 @@ async def build_context(self) -> InjectionContext: # DIDComm Messaging if context.settings.get("experiment.didcomm_v2"): + LOGGER.info("DIDComm v2 experimental mode enabled") from didcomm_messaging import CryptoService, PackagingService, RoutingService from didcomm_messaging.crypto.backend.askar import AskarCryptoService @@ -81,6 +85,7 @@ async def build_context(self) -> InjectionContext: async def bind_providers(self, context: InjectionContext): """Bind various class providers.""" + LOGGER.debug("Begin binding providers to context") context.injector.bind_provider(ProfileManager, ProfileManagerProvider()) @@ -88,12 +93,7 @@ async def bind_providers(self, context: InjectionContext): context.injector.bind_provider( BaseWireFormat, CachedProvider( - # StatsProvider( ClassProvider("acapy_agent.transport.pack_format.PackWireFormat"), - # ( - # "encode_message", "parse_message" - # ), - # ) ), ) @@ -110,6 +110,7 @@ async def bind_providers(self, context: InjectionContext): async def load_plugins(self, context: InjectionContext): """Set up plugin registry and load plugins.""" + LOGGER.debug("Initializing plugin registry") plugin_registry = PluginRegistry( blocklist=self.settings.get("blocked_plugins", []) ) @@ -183,6 +184,7 @@ def register_anoncreds_plugins(): # Register external plugins for plugin_path in self.settings.get("external_plugins", []): + LOGGER.debug("Registering external plugin: %s", plugin_path) plugin_registry.register_plugin(plugin_path) # Register message protocols diff --git a/acapy_agent/config/ledger.py b/acapy_agent/config/ledger.py index 6cda513ba6..e177d37fc8 100644 --- a/acapy_agent/config/ledger.py +++ b/acapy_agent/config/ledger.py @@ -33,14 +33,18 @@ async def fetch_genesis_transactions(genesis_url: str) -> str: # https://github.com/openwallet-foundation/acapy/issues/1745 return await fetch(genesis_url, headers=headers, max_attempts=20) except FetchError as e: + LOGGER.error("Error retrieving genesis transactions from %s: %s", genesis_url, e) raise ConfigError("Error retrieving ledger genesis transactions") from e async def get_genesis_transactions(settings: Settings) -> str: """Fetch genesis transactions if necessary.""" + LOGGER.debug("Getting genesis transactions from settings") txns = settings.get("ledger.genesis_transactions") + LOGGER.debug("Genesis transactions from settings: %s", "found" if txns else "absent") if not txns: + LOGGER.debug("No genesis transactions found in settings") if settings.get("ledger.genesis_url"): txns = await fetch_genesis_transactions(settings["ledger.genesis_url"]) elif settings.get("ledger.genesis_file"): @@ -50,8 +54,10 @@ async def get_genesis_transactions(settings: Settings) -> str: with open(genesis_path, "r") as genesis_file: txns = genesis_file.read() except IOError as e: + LOGGER.error("Failed to read genesis file: %s", str(e)) raise ConfigError("Error reading ledger genesis transactions") from e if txns: + LOGGER.debug("Storing genesis transactions in settings") settings["ledger.genesis_transactions"] = txns return txns @@ -62,6 +68,8 @@ async def load_multiple_genesis_transactions_from_config(settings: Settings): ledger_config_list = settings.get("ledger.ledger_config_list") ledger_txns_list = [] write_ledger_set = False + LOGGER.debug("Processing %d ledger configs", len(ledger_config_list)) + for config in ledger_config_list: txns = None if "genesis_transactions" in config: @@ -73,11 +81,12 @@ async def load_multiple_genesis_transactions_from_config(settings: Settings): try: genesis_path = config.get("genesis_file") LOGGER.info( - "Reading ledger genesis transactions from: %s", genesis_path + "Reading ledger genesis transactions from file: %s", genesis_path ) with open(genesis_path, "r") as genesis_file: txns = genesis_file.read() except IOError as e: + LOGGER.error("Failed to read genesis file: %s", str(e)) raise ConfigError("Error reading ledger genesis transactions") from e is_write_ledger = ( False if config.get("is_write") is None else config.get("is_write") @@ -118,6 +127,7 @@ async def load_multiple_genesis_transactions_from_config(settings: Settings): " genesis_file and genesis_transactions provided." ) settings["ledger.ledger_config_list"] = ledger_txns_list + LOGGER.debug("Processed %d ledger configs successfully", len(ledger_txns_list)) async def ledger_config( @@ -125,6 +135,10 @@ async def ledger_config( ) -> bool: """Perform Indy ledger configuration.""" + LOGGER.debug( + "Configuring ledger for profile %s and public_did %s", profile.name, public_did + ) + session = await profile.session() ledger = session.inject_or(BaseLedger) @@ -135,32 +149,46 @@ async def ledger_config( async with ledger: # Check transaction author agreement acceptance if not ledger.read_only: + LOGGER.debug("Checking transaction author agreement") taa_info = await ledger.get_txn_author_agreement() if taa_info["taa_required"] and public_did: + LOGGER.debug("TAA acceptance required") taa_accepted = await ledger.get_latest_txn_author_acceptance() if ( not taa_accepted or taa_info["taa_record"]["digest"] != taa_accepted["digest"] ): + LOGGER.info("TAA acceptance needed - performing acceptance") if not await accept_taa(ledger, profile, taa_info, provision): + LOGGER.warning("TAA acceptance failed") return False + LOGGER.info("TAA acceptance completed") # Publish endpoints if necessary - skipped if TAA is required but not accepted endpoint = session.settings.get("default_endpoint") if public_did: wallet = session.inject(BaseWallet) try: + LOGGER.debug("Setting DID endpoint to: %s", endpoint) await wallet.set_did_endpoint(public_did, endpoint, ledger) except LedgerError as x_ledger: + LOGGER.error("Error setting DID endpoint: %s", x_ledger.message) raise ConfigError(x_ledger.message) from x_ledger # e.g., read-only # Publish profile endpoint if ledger is NOT read-only profile_endpoint = session.settings.get("profile_endpoint") if profile_endpoint and not ledger.read_only: + LOGGER.debug( + "Publishing profile endpoint: %s for DID: %s", + profile_endpoint, + public_did, + ) await ledger.update_endpoint_for_did( public_did, profile_endpoint, EndpointType.PROFILE ) + LOGGER.info("Profile endpoint published successfully") + LOGGER.info("Ledger configuration complete") return True diff --git a/acapy_agent/config/logging/configurator.py b/acapy_agent/config/logging/configurator.py index 680fb92c2e..5f7de2e37e 100644 --- a/acapy_agent/config/logging/configurator.py +++ b/acapy_agent/config/logging/configurator.py @@ -32,6 +32,8 @@ TimedRotatingFileMultiProcessHandler, ) +LOGGER = logging.getLogger(__name__) + def load_resource(path: str, encoding: Optional[str] = None): """Open a resource file located in a python package or the local filesystem. @@ -57,7 +59,8 @@ def load_resource(path: str, encoding: Optional[str] = None): return io.TextIOWrapper(bstream, encoding=encoding) return bstream except IOError: - pass + LOGGER.warning("Resource not found: %s", path) + return None def dictConfig(config, new_file_path=None): @@ -95,18 +98,7 @@ def fileConfig( raise RuntimeError(f"{fname} is invalid: {e}") if new_file_path and cp.has_section("handler_timed_file_handler"): - cp.set( - "handler_timed_file_handler", - "args", - str( - ( - f"{new_file_path}", - "d", - 7, - 1, - ) - ), - ) + cp.set("handler_timed_file_handler", "args", str((new_file_path, "d", 7, 1))) formatters = _create_formatters(cp) with logging._lock: diff --git a/acapy_agent/core/conductor.py b/acapy_agent/core/conductor.py index 3459f32d8e..ca6252d5b0 100644 --- a/acapy_agent/core/conductor.py +++ b/acapy_agent/core/conductor.py @@ -119,41 +119,60 @@ def context(self) -> InjectionContext: async def setup(self): """Initialize the global request context.""" + LOGGER.debug("Starting setup of the Conductor") context = await self.context_builder.build_context() + LOGGER.debug("Context built successfully") if self.force_agent_anoncreds: + LOGGER.debug( + "Force agent anoncreds is enabled. " + "Setting wallet type to 'askar-anoncreds'." + ) context.settings.set_value("wallet.type", "askar-anoncreds") # Fetch genesis transactions if necessary if context.settings.get("ledger.ledger_config_list"): + LOGGER.debug( + "Ledger config list found. Loading multiple genesis transactions" + ) await load_multiple_genesis_transactions_from_config(context.settings) if ( context.settings.get("ledger.genesis_transactions") or context.settings.get("ledger.genesis_file") or context.settings.get("ledger.genesis_url") ): + LOGGER.debug( + "Genesis transactions/configurations found. Fetching genesis transactions" + ) await get_genesis_transactions(context.settings) # Configure the root profile + LOGGER.debug("Configuring the root profile and setting up public DID") self.root_profile, self.setup_public_did = await wallet_config(context) context = self.root_profile.context + LOGGER.debug("Root profile configured successfully") # Multiledger Setup - if ( - context.settings.get("ledger.ledger_config_list") - and len(context.settings.get("ledger.ledger_config_list")) > 0 - ): + ledger_config_list = context.settings.get("ledger.ledger_config_list") + if ledger_config_list and len(ledger_config_list) > 0: + LOGGER.debug("Setting up multiledger manager") context.injector.bind_provider( BaseMultipleLedgerManager, MultiIndyLedgerManagerProvider(self.root_profile), ) - if not (context.settings.get("ledger.genesis_transactions")): + if not context.settings.get("ledger.genesis_transactions"): ledger = context.injector.inject(BaseLedger) + LOGGER.debug( + "Ledger backend: %s, Profile backend: %s", + ledger.BACKEND_NAME, + self.root_profile.BACKEND_NAME, + ) if ( self.root_profile.BACKEND_NAME == "askar" and ledger.BACKEND_NAME == "indy-vdr" ): + LOGGER.debug("Binding IndyCredxVerifier for 'askar' backend.") context.injector.bind_provider( IndyVerifier, ClassProvider( @@ -165,6 +184,9 @@ async def setup(self): self.root_profile.BACKEND_NAME == "askar-anoncreds" and ledger.BACKEND_NAME == "indy-vdr" ): + LOGGER.debug( + "Binding IndyCredxVerifier for 'askar-anoncreds' backend." + ) context.injector.bind_provider( IndyVerifier, ClassProvider( @@ -173,6 +195,7 @@ async def setup(self): ), ) else: + LOGGER.error("Unsupported ledger backend for multiledger setup.") raise MultipleLedgerManagerError( "Multiledger is supported only for Indy SDK or Askar " "[Indy VDR] profile" @@ -182,13 +205,17 @@ async def setup(self): ) # Configure the ledger - if not await ledger_config( + ledger_configured = await ledger_config( self.root_profile, self.setup_public_did and self.setup_public_did.did - ): - LOGGER.warning("No ledger configured") + ) + if not ledger_configured: + LOGGER.warning("No ledger configured.") + else: + LOGGER.debug("Ledger configured successfully.") if not context.settings.get("transport.disabled"): # Register all inbound transports if enabled + LOGGER.debug("Transport not disabled. Setting up inbound transports.") self.inbound_transport_manager = InboundTransportManager( self.root_profile, self.inbound_message_router, self.handle_not_returned ) @@ -196,45 +223,54 @@ async def setup(self): context.injector.bind_instance( InboundTransportManager, self.inbound_transport_manager ) + LOGGER.debug("Inbound transports registered successfully.") - if not context.settings.get("transport.disabled"): # Register all outbound transports + LOGGER.debug("Setting up outbound transports.") self.outbound_transport_manager = OutboundTransportManager( self.root_profile, self.handle_not_delivered ) await self.outbound_transport_manager.setup() + LOGGER.debug("Outbound transports registered successfully.") # Initialize dispatcher + LOGGER.debug("Initializing dispatcher.") self.dispatcher = Dispatcher(self.root_profile) await self.dispatcher.setup() + LOGGER.debug("Dispatcher initialized successfully.") wire_format = context.inject_or(BaseWireFormat) if wire_format and hasattr(wire_format, "task_queue"): wire_format.task_queue = self.dispatcher.task_queue + LOGGER.debug("Wire format task queue bound to dispatcher.") # Bind manager for multitenancy related tasks if context.settings.get("multitenant.enabled"): + LOGGER.debug("Multitenant is enabled. Binding MultitenantManagerProvider.") context.injector.bind_provider( BaseMultitenantManager, MultitenantManagerProvider(self.root_profile) ) # Bind route manager provider + LOGGER.debug("Binding RouteManagerProvider.") context.injector.bind_provider( RouteManager, RouteManagerProvider(self.root_profile) ) - # Bind oob message processor to be able to receive and process un-encrypted - # messages + # Bind OobMessageProcessor to be able to receive and process unencrypted messages + LOGGER.debug("Binding OobMessageProcessor.") context.injector.bind_instance( OobMessageProcessor, OobMessageProcessor(inbound_message_router=self.inbound_message_router), ) # Bind default PyLD document loader + LOGGER.debug("Binding default DocumentLoader.") context.injector.bind_instance(DocumentLoader, DocumentLoader(self.root_profile)) # Admin API if context.settings.get("admin.enabled"): + LOGGER.debug("Admin API is enabled. Attempting to register admin server.") try: admin_host = context.settings.get("admin.host", "0.0.0.0") admin_port = context.settings.get("admin.port", "80") @@ -250,13 +286,15 @@ async def setup(self): self.get_stats, ) context.injector.bind_instance(BaseAdminServer, self.admin_server) + LOGGER.debug("Admin server registered on %s:%s", admin_host, admin_port) except Exception: - LOGGER.exception("Unable to register admin server") + LOGGER.exception("Unable to register admin server.") raise # Fetch stats collector, if any collector = context.inject_or(Collector) if collector: + LOGGER.debug("Stats collector found. Wrapping methods for collection.") # add stats to our own methods collector.wrap( self, @@ -275,33 +313,41 @@ async def setup(self): "find_inbound_connection", ), ) + LOGGER.debug("Methods wrapped with stats collector.") async def start(self) -> None: """Start the agent.""" - + LOGGER.debug("Starting the Conductor agent.") assert self.root_profile, "root_profile is not set" context = self.root_profile.context await self.check_for_valid_wallet_type(self.root_profile) + LOGGER.debug("Wallet type validated.") if not context.settings.get("transport.disabled"): # Start up transports if enabled try: + LOGGER.debug("Transport not disabled. Starting inbound transports.") await self.inbound_transport_manager.start() + LOGGER.debug("Inbound transports started successfully.") except Exception: - LOGGER.exception("Unable to start inbound transports") + LOGGER.exception("Unable to start inbound transports.") raise try: + LOGGER.debug("Starting outbound transports.") await self.outbound_transport_manager.start() + LOGGER.debug("Outbound transports started successfully.") except Exception: - LOGGER.exception("Unable to start outbound transports") + LOGGER.exception("Unable to start outbound transports.") raise # Start up Admin server if self.admin_server: + LOGGER.debug("Admin server present. Starting admin server.") try: await self.admin_server.start() + LOGGER.debug("Admin server started successfully.") except Exception: - LOGGER.exception("Unable to start administration API") + LOGGER.exception("Unable to start administration API.") # Make admin responder available during message parsing # This allows webhooks to be called when a connection is marked active, # for example @@ -310,9 +356,11 @@ async def start(self) -> None: self.admin_server.outbound_message_router, ) context.injector.bind_instance(BaseResponder, responder) + LOGGER.debug("Admin responder bound to injector.") # Get agent label default_label = context.settings.get("default_label") + LOGGER.debug("Agent label: %s", default_label) if context.settings.get("transport.disabled"): LoggingConfigurator.print_banner( @@ -337,6 +385,7 @@ async def start(self) -> None: from_version_storage = None from_version = None agent_version = f"v{__version__}" + LOGGER.debug("Recording ACA-Py version in wallet if needed.") async with self.root_profile.session() as session: storage: BaseStorage = session.context.inject(BaseStorage) try: @@ -351,10 +400,16 @@ async def start(self) -> None: ) except StorageNotFoundError: LOGGER.warning("Wallet version storage record not found.") + from_version_config = self.root_profile.settings.get("upgrade.from_version") force_upgrade_flag = ( self.root_profile.settings.get("upgrade.force_upgrade") or False ) + LOGGER.debug( + "Force upgrade flag: %s, From version config: %s", + force_upgrade_flag, + from_version_config, + ) if force_upgrade_flag and from_version_config: if from_version_storage: @@ -366,8 +421,13 @@ async def start(self) -> None: from_version = from_version_storage else: from_version = from_version_config + LOGGER.debug( + "Determined from_version based on force_upgrade: %s", from_version + ) else: from_version = from_version_storage or from_version_config + LOGGER.debug("Determined from_version: %s", from_version) + if not from_version: LOGGER.warning( ( @@ -378,17 +438,27 @@ async def start(self) -> None: ) from_version = DEFAULT_ACAPY_VERSION self.root_profile.settings.set_value("upgrade.from_version", from_version) + LOGGER.debug("Set upgrade.from_version to default: %s", from_version) + config_available_list = get_upgrade_version_list( config_path=self.root_profile.settings.get("upgrade.config_path"), from_version=from_version, ) + LOGGER.debug("Available upgrade versions: %s", config_available_list) + if len(config_available_list) >= 1: + LOGGER.info("Upgrade configurations available. Initiating upgrade.") await upgrade(profile=self.root_profile) elif not (from_version_storage and from_version_storage == agent_version): + LOGGER.debug("No upgrades needed. Adding version record.") await add_version_record(profile=self.root_profile, version=agent_version) # Create a static connection for use by the test-suite if context.settings.get("debug.test_suite_endpoint"): + LOGGER.debug( + "Test suite endpoint configured. " + "Creating static connection for test suite." + ) mgr = BaseConnectionManager(self.root_profile) their_endpoint = context.settings["debug.test_suite_endpoint"] _, _, test_conn = await mgr.create_static_connection( @@ -397,32 +467,38 @@ async def start(self) -> None: their_endpoint=their_endpoint, alias="test-suite", ) - print("Created static connection for test suite") - print(" - My DID:", test_conn.my_did) - print(" - Their DID:", test_conn.their_did) - print(" - Their endpoint:", their_endpoint) - print() + LOGGER.info( + "Created static connection for test suite\n" + f" - My DID: {test_conn.my_did}\n" + f" - Their DID: {test_conn.their_did}\n" + f" - Their endpoint: {their_endpoint}\n" + ) del mgr + LOGGER.debug("Static connection for test suite created and manager deleted.") # Clear default mediator if context.settings.get("mediation.clear"): + LOGGER.debug("Mediation clear flag set. Clearing default mediator.") mediation_mgr = MediationManager(self.root_profile) await mediation_mgr.clear_default_mediator() - print("Default mediator cleared.") + LOGGER.info("Default mediator cleared.") - # Clear default mediator # Set default mediator by id default_mediator_id = context.settings.get("mediation.default_id") if default_mediator_id: + LOGGER.debug("Setting default mediator to ID: %s", default_mediator_id) mediation_mgr = MediationManager(self.root_profile) try: await mediation_mgr.set_default_mediator_by_id(default_mediator_id) - print(f"Default mediator set to {default_mediator_id}") + LOGGER.info(f"Default mediator set to {default_mediator_id}") except Exception: - LOGGER.exception("Error updating default mediator") + LOGGER.exception("Error updating default mediator.") # Print an invitation to the terminal if context.settings.get("debug.print_invitation"): + LOGGER.debug( + "Debug flag for printing invitation is set. Creating invitation." + ) try: mgr = OutOfBandManager(self.root_profile) invi_rec = await mgr.create_invitation( @@ -436,17 +512,17 @@ async def start(self) -> None: ) base_url = context.settings.get("invite_base_url") invite_url = invi_rec.invitation.to_url(base_url) - print("Invitation URL:") - print(invite_url, flush=True) + LOGGER.info(f"Invitation URL:\n{invite_url}") qr = QRCode(border=1) qr.add_data(invite_url) qr.print_ascii(invert=True) del mgr except Exception: - LOGGER.exception("Error creating invitation") + LOGGER.exception("Error creating invitation.") # mediation connection establishment provided_invite: str = context.settings.get("mediation.invite") + LOGGER.debug("Mediation invite provided: %s", provided_invite) try: async with self.root_profile.session() as session: @@ -454,19 +530,28 @@ async def start(self) -> None: mediation_invite_record = await invite_store.get_mediation_invite_record( provided_invite ) + LOGGER.debug("Mediation invite record retrieved successfully.") except Exception: - LOGGER.exception("Error retrieving mediator invitation") + LOGGER.exception("Error retrieving mediator invitation.") mediation_invite_record = None # Accept mediation invitation if one was specified or stored if mediation_invite_record is not None: + LOGGER.debug( + "Mediation invite record found. " + "Attempting to accept mediation invitation." + ) try: if not mediation_invite_record.used: - # clear previous mediator configuration before establishing a - # new one + # clear previous mediator configuration before establishing a new one + LOGGER.debug( + "Mediation invite not used. " + "Clearing default mediator before accepting new invite." + ) await MediationManager(self.root_profile).clear_default_mediator() mgr = OutOfBandManager(self.root_profile) + LOGGER.debug("Receiving mediation invitation.") record = await mgr.receive_invitation( invitation=InvitationMessage.from_url( mediation_invite_record.invite @@ -477,6 +562,7 @@ async def start(self) -> None: await MediationInviteStore( session.context.inject(BaseStorage) ).mark_default_invite_as_used() + LOGGER.debug("Marked mediation invite as used.") await record.metadata_set( session, MediationManager.SEND_REQ_AFTER_CONNECTION, True @@ -484,48 +570,65 @@ async def start(self) -> None: await record.metadata_set( session, MediationManager.SET_TO_DEFAULT_ON_GRANTED, True ) + LOGGER.debug("Set mediation metadata after connection.") - print("Attempting to connect to mediator...") + LOGGER.info("Attempting to connect to mediator...") del mgr + LOGGER.debug("Mediation manager deleted after setting up mediator.") except Exception: - LOGGER.exception("Error accepting mediation invitation") + LOGGER.exception("Error accepting mediation invitation.") try: + LOGGER.debug("Checking for wallet upgrades in progress.") await self.check_for_wallet_upgrades_in_progress() + LOGGER.debug("Wallet upgrades check completed.") except Exception: LOGGER.exception( - "An exception was caught while checking for wallet upgrades in progress" + "An exception was caught while checking for wallet upgrades in progress." ) # notify protocols of startup status + LOGGER.debug("Notifying protocols of startup status.") await self.root_profile.notify(STARTUP_EVENT_TOPIC, {}) + LOGGER.debug("Startup notification sent.") async def stop(self, timeout=1.0): """Stop the agent.""" + LOGGER.info("Stopping the Conductor agent.") # notify protocols that we are shutting down if self.root_profile: + LOGGER.debug("Notifying protocols of shutdown.") await self.root_profile.notify(SHUTDOWN_EVENT_TOPIC, {}) + LOGGER.debug("Shutdown notification sent.") shutdown = TaskQueue() if self.dispatcher: + LOGGER.debug("Initiating shutdown of dispatcher.") shutdown.run(self.dispatcher.complete()) if self.admin_server: + LOGGER.debug("Initiating shutdown of admin server.") shutdown.run(self.admin_server.stop()) if self.inbound_transport_manager: + LOGGER.debug("Initiating shutdown of inbound transport manager.") shutdown.run(self.inbound_transport_manager.stop()) if self.outbound_transport_manager: + LOGGER.debug("Initiating shutdown of outbound transport manager.") shutdown.run(self.outbound_transport_manager.stop()) if self.root_profile: # close multitenant profiles multitenant_mgr = self.context.inject_or(BaseMultitenantManager) if multitenant_mgr: + LOGGER.debug("Closing multitenant profiles.") for profile in multitenant_mgr.open_profiles: + LOGGER.debug("Closing profile: %s", profile.name) shutdown.run(profile.close()) - + LOGGER.debug("Closing root profile.") shutdown.run(self.root_profile.close()) + LOGGER.debug("Waiting for shutdown tasks to complete with timeout=%f.", timeout) await shutdown.complete(timeout) + LOGGER.info("Conductor agent stopped successfully.") def inbound_message_router( self, diff --git a/acapy_agent/core/dispatcher.py b/acapy_agent/core/dispatcher.py index 962b69d97c..dfa476e444 100644 --- a/acapy_agent/core/dispatcher.py +++ b/acapy_agent/core/dispatcher.py @@ -176,9 +176,6 @@ async def handle_v1_message( inbound_message: The inbound message instance send_outbound: Async function to send outbound messages - # Raises: - # MessageParseError: If the message type version is not supported - Returns: The response from the handler @@ -193,7 +190,9 @@ async def handle_v1_message( except ProblemReportParseError: pass # avoid problem report recursion except MessageParseError as e: - self.logger.error(f"Message parsing failed: {str(e)}, sending problem report") + self.logger.error( + f"Message parsing failed: {str(e)}, sending problem report", exc_info=e + ) error_result = ProblemReport( description={ "en": str(e), diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index b3fa709386..685ef86898 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -3,7 +3,7 @@ import logging from collections import OrderedDict from types import ModuleType -from typing import Iterable, Optional, Sequence +from typing import Optional, Sequence, Set from ..config.injection_context import InjectionContext from ..core.event_bus import EventBus @@ -18,10 +18,10 @@ class PluginRegistry: """Plugin registry for indexing application plugins.""" - def __init__(self, blocklist: Iterable[str] = []): + def __init__(self, blocklist: Optional[Set[str]] = None): """Initialize a `PluginRegistry` instance.""" - self._plugins = OrderedDict() - self._blocklist = set(blocklist) + self._plugins: OrderedDict[str, ModuleType] = OrderedDict() + self._blocklist: Set[str] = set(blocklist) if blocklist else set() @property def plugin_names(self) -> Sequence[str]: @@ -57,7 +57,6 @@ def validate_version(self, version_list, module_name): for version_dict in version_list: # Dicts must have correct format - try: if not ( isinstance(version_dict["major_version"], int) @@ -89,8 +88,8 @@ def validate_version(self, version_list, module_name): > version_dict["current_minor_version"] ): raise ProtocolDefinitionValidationError( - "Minimum supported minor version cannot" - + " be greater than current minor version" + "Minimum supported minor version cannot " + "be greater than current minor version" ) # There can only be one definition per major version @@ -102,7 +101,7 @@ def validate_version(self, version_list, module_name): if count > 1: raise ProtocolDefinitionValidationError( "There can only be one definition per major version. " - + f"Found {count} for major version {major_version}." + f"Found {count} for major version {major_version}." ) # Specified module must be loadable @@ -111,97 +110,129 @@ def validate_version(self, version_list, module_name): if not mod: raise ProtocolDefinitionValidationError( - "Version module path is not " - + f"loadable: {module_name}, {version_path}" + f"Version module path is not loadable: {module_name}, {version_path}" ) return True - def register_plugin(self, module_name: str) -> ModuleType: + def register_plugin(self, module_name: str) -> Optional[ModuleType]: """Register a plugin module.""" - if module_name in self._plugins: - mod = self._plugins[module_name] - elif module_name in self._blocklist: - LOGGER.debug(f"Blocked {module_name} from loading due to blocklist") + if self._is_already_registered(module_name): + return self._plugins.get(module_name) + + if self._is_blocked(module_name): return None - else: - try: - mod = ClassLoader.load_module(module_name) - LOGGER.debug(f"Loaded module: {module_name}") - except ModuleLoadError as e: - LOGGER.error(f"Error loading plugin module: {e}") - return None - # Module must exist - if not mod: - LOGGER.error(f"Module doesn't exist: {module_name}") - return None - - # Any plugin with a setup method is considered valid. - if hasattr(mod, "setup"): - self._plugins[module_name] = mod - return mod - - # Make an exception for non-protocol modules - # that contain admin routes and for old-style protocol - # modules without version support - routes = ClassLoader.load_module("routes", module_name) - message_types = ClassLoader.load_module("message_types", module_name) - if routes or message_types: - self._plugins[module_name] = mod - return mod - - definition = ClassLoader.load_module("definition", module_name) - - # definition.py must exist in protocol - if not definition: - LOGGER.error(f"Protocol does not include definition.py: {module_name}") - return None - - # definition.py must include versions attribute - if not hasattr(definition, "versions"): - LOGGER.error( - "Protocol definition does not include " - f"versions attribute: {module_name}" - ) - return None + mod = self._load_module(module_name) + if not mod: + LOGGER.error("Module doesn't exist: %s", module_name) + return None - # Definition list must not be malformed - try: - self.validate_version(definition.versions, module_name) - except ProtocolDefinitionValidationError as e: - LOGGER.error(f"Protocol versions definition is malformed. {e}") - return None + if self._is_valid_plugin(mod, module_name): + self._plugins[module_name] = mod + LOGGER.debug("Registered plugin: %s", module_name) + return mod - self._plugins[module_name] = mod - return mod + LOGGER.warning("Failed to register plugin: %s", module_name) + return None - # # Load each version as a separate plugin - # for version in definition.versions: - # mod = ClassLoader.load_module(f"{module_name}.{version['path']}") - # self._plugins[module_name] = mod - # return mod + def _is_already_registered(self, module_name: str) -> bool: + """Check if the plugin is already registered.""" + if module_name in self._plugins: + LOGGER.debug("Plugin %s is already registered.", module_name) + return True + return False + + def _is_blocked(self, module_name: str) -> bool: + """Check if the plugin is in the blocklist.""" + if module_name in self._blocklist: + LOGGER.debug("Blocked %s from loading due to blocklist.", module_name) + return True + return False + + def _load_module(self, module_name: str) -> Optional[ModuleType]: + """Load the plugin module using ClassLoader.""" + try: + mod = ClassLoader.load_module(module_name) + return mod + except ModuleLoadError as e: + LOGGER.error("Error loading plugin module '%s': %s", module_name, e) + return None + + def _is_valid_plugin(self, mod: ModuleType, module_name: str) -> bool: + """Validate the plugin based on various criteria.""" + # Check if the plugin has a 'setup' method + if hasattr(mod, "setup"): + return True + + # Check for 'routes' or 'message_types' modules + # This makes an exception for non-protocol modules that contain admin routes + # and for old-style protocol modules without version support + routes = ClassLoader.load_module("routes", module_name) + message_types = ClassLoader.load_module("message_types", module_name) + if routes or message_types: + return True + + # Check for 'definition' module with 'versions' attribute + definition = ClassLoader.load_module("definition", module_name) + + # definition.py must exist in protocol + if not definition: + LOGGER.error( + "Protocol does not include 'definition.py' for module: %s", + module_name, + ) + return False + + # definition.py must include versions attribute + if not hasattr(definition, "versions"): + LOGGER.error( + "Protocol definition does not include versions attribute for module: %s", + module_name, + ) + return False + + # Validate the 'versions' attribute + try: + self.validate_version(definition.versions, module_name) + return True + except ProtocolDefinitionValidationError as e: + LOGGER.error( + "Protocol versions definition is malformed for module '%s': %s", + module_name, + e, + ) + return False def register_package(self, package_name: str) -> Sequence[ModuleType]: """Register all modules (sub-packages) under a given package name.""" + LOGGER.debug("Registering package: %s", package_name) try: module_names = ClassLoader.scan_subpackages(package_name) except ModuleLoadError: LOGGER.error("Plugin module package not found: %s", package_name) module_names = [] - return list( - filter( - None, - ( - self.register_plugin(module_name) - for module_name in module_names - if module_name.split(".")[-1] != "tests" - ), - ) - ) - async def init_context(self, context: InjectionContext): + registered_plugins = [] + for module_name in module_names: + # Skip any module whose last segment is 'tests' + if module_name.split(".")[-1] == "tests": + continue + + plugin = self.register_plugin(module_name) + if plugin: + registered_plugins.append(plugin) + else: + LOGGER.warning( + "Failed to register %s under %s", module_name, package_name + ) + + return registered_plugins + + async def init_context(self, context: InjectionContext) -> None: """Call plugin setup methods on the current context.""" + LOGGER.debug("Initializing plugin context for %d plugins", len(self._plugins)) + for plugin in self._plugins.values(): if hasattr(plugin, "setup"): await plugin.setup(context) @@ -216,25 +247,29 @@ async def load_protocol_version( context: InjectionContext, mod: ModuleType, version_definition: Optional[dict] = None, - ): + ) -> None: """Load a particular protocol version.""" protocol_registry = context.inject(ProtocolRegistry) goal_code_registry = context.inject(GoalCodeRegistry) + if hasattr(mod, "MESSAGE_TYPES"): protocol_registry.register_message_types( mod.MESSAGE_TYPES, version_definition=version_definition ) + if hasattr(mod, "CONTROLLERS"): protocol_registry.register_controllers(mod.CONTROLLERS) goal_code_registry.register_controllers(mod.CONTROLLERS) - async def load_protocols(self, context: InjectionContext, plugin: ModuleType): + async def load_protocols(self, context: InjectionContext, plugin: ModuleType) -> None: """For modules that don't implement setup, register protocols manually.""" + plugin_name = plugin.__name__ # If this module contains message_types, then assume that # this is a valid module of the old style (not versioned) try: - mod = ClassLoader.load_module(plugin.__name__ + ".message_types") + message_types_path = f"{plugin_name}.message_types" + mod = ClassLoader.load_module(message_types_path) except ModuleLoadError as e: LOGGER.error("Error loading plugin module message types: %s", e) return @@ -242,106 +277,134 @@ async def load_protocols(self, context: InjectionContext, plugin: ModuleType): if mod: await self.load_protocol_version(context, mod) else: - # Otherwise, try check for definition.py for versioned - # protocol packages + # Otherwise, try check for definition.py for versioned protocol packages try: - definition = ClassLoader.load_module(plugin.__name__ + ".definition") + definition_path = f"{plugin_name}.definition" + definition = ClassLoader.load_module(definition_path) except ModuleLoadError as e: LOGGER.error("Error loading plugin definition module: %s", e) return if definition: for protocol_version in definition.versions: + version_path = ( + f"{plugin_name}.{protocol_version['path']}.message_types" + ) try: - mod = ClassLoader.load_module( - f"{plugin.__name__}.{protocol_version['path']}" - + ".message_types" - ) - await self.load_protocol_version(context, mod, protocol_version) - + mod = ClassLoader.load_module(version_path) except ModuleLoadError as e: - LOGGER.error("Error loading plugin module message types: %s", e) + LOGGER.error( + "Error loading plugin module message types from %s: %s", + version_path, + e, + ) return - async def register_admin_routes(self, app): + if mod: + await self.load_protocol_version(context, mod, protocol_version) + else: + LOGGER.debug("Failed to load %s", version_path) + + async def register_admin_routes(self, app) -> None: """Call route registration methods on the current context.""" + LOGGER.debug("Registering admin routes for %d plugins", len(self._plugins)) + for plugin in self._plugins.values(): - definition = ClassLoader.load_module("definition", plugin.__name__) + plugin_name = plugin.__name__ + mod = None + definition = ClassLoader.load_module("definition", plugin_name) if definition: # Load plugin routes that are in a versioned package. for plugin_version in definition.versions: + version_path = f"{plugin_name}.{plugin_version['path']}.routes" try: - mod = ClassLoader.load_module( - f"{plugin.__name__}.{plugin_version['path']}.routes" - ) + mod = ClassLoader.load_module(version_path) except ModuleLoadError as e: - LOGGER.error("Error loading admin routes: %s", e) + LOGGER.error( + "Error loading admin routes from %s: %s", version_path, e + ) continue + if mod and hasattr(mod, "register"): await mod.register(app) else: # Load plugin routes that aren't in a versioned package. + routes_path = f"{plugin_name}.routes" try: - mod = ClassLoader.load_module(f"{plugin.__name__}.routes") + mod = ClassLoader.load_module(routes_path) except ModuleLoadError as e: - LOGGER.error("Error loading admin routes: %s", e) + LOGGER.error("Error loading admin routes from %s: %s", routes_path, e) continue + if mod and hasattr(mod, "register"): await mod.register(app) - def register_protocol_events(self, context: InjectionContext): + def register_protocol_events(self, context: InjectionContext) -> None: """Call route register_events methods on the current context.""" + LOGGER.debug("Registering protocol events for %d plugins", len(self._plugins)) + event_bus = context.inject_or(EventBus) if not event_bus: LOGGER.error("No event bus in context") return + for plugin in self._plugins.values(): - definition = ClassLoader.load_module("definition", plugin.__name__) + plugin_name = plugin.__name__ + mod = None + definition = ClassLoader.load_module("definition", plugin_name) if definition: # Load plugin routes that are in a versioned package. for plugin_version in definition.versions: + version_path = f"{plugin_name}.{plugin_version['path']}.routes" try: - mod = ClassLoader.load_module( - f"{plugin.__name__}.{plugin_version['path']}.routes" - ) + mod = ClassLoader.load_module(version_path) except ModuleLoadError as e: - LOGGER.error("Error loading admin routes: %s", e) + LOGGER.error("Error loading events from %s: %s", version_path, e) continue + if mod and hasattr(mod, "register_events"): mod.register_events(event_bus) else: # Load plugin routes that aren't in a versioned package. + routes_path = f"{plugin_name}.routes" try: - mod = ClassLoader.load_module(f"{plugin.__name__}.routes") + mod = ClassLoader.load_module(routes_path) except ModuleLoadError as e: - LOGGER.error("Error loading admin routes: %s", e) + LOGGER.error("Error loading events from %s: %s", routes_path, e) continue + if mod and hasattr(mod, "register_events"): mod.register_events(event_bus) - def post_process_routes(self, app): + def post_process_routes(self, app) -> None: """Call route binary file response OpenAPI fixups if applicable.""" + LOGGER.debug("Post-processing routes for %d plugins", len(self._plugins)) + for plugin in self._plugins.values(): - definition = ClassLoader.load_module("definition", plugin.__name__) + plugin_name = plugin.__name__ + mod = None + definition = ClassLoader.load_module("definition", plugin_name) if definition: # Set binary file responses for routes that are in a versioned package. for plugin_version in definition.versions: + version_path = f"{plugin_name}.{plugin_version['path']}.routes" try: - mod = ClassLoader.load_module( - f"{plugin.__name__}.{plugin_version['path']}.routes" - ) + mod = ClassLoader.load_module(version_path) except ModuleLoadError as e: - LOGGER.error("Error loading admin routes: %s", e) + LOGGER.error("Error loading routes from %s: %s", version_path, e) continue + if mod and hasattr(mod, "post_process_routes"): mod.post_process_routes(app) else: # Set binary file responses for routes not in a versioned package. + routes_path = f"{plugin_name}.routes" try: - mod = ClassLoader.load_module(f"{plugin.__name__}.routes") + mod = ClassLoader.load_module(routes_path) except ModuleLoadError as e: - LOGGER.error("Error loading admin routes: %s", e) + LOGGER.error("Error loading routes from %s: %s", routes_path, e) continue + if mod and hasattr(mod, "post_process_routes"): mod.post_process_routes(app) diff --git a/acapy_agent/core/tests/test_plugin_registry.py b/acapy_agent/core/tests/test_plugin_registry.py index b5727a4546..4e870fbdfb 100644 --- a/acapy_agent/core/tests/test_plugin_registry.py +++ b/acapy_agent/core/tests/test_plugin_registry.py @@ -537,6 +537,7 @@ async def test_load_protocols_load_mod(self): mock_mod = mock.MagicMock() mock_mod.MESSAGE_TYPES = mock.MagicMock() mock_mod.CONTROLLERS = mock.MagicMock() + mock_mod.__name__ = "test_mod" with mock.patch.object( ClassLoader, "load_module", mock.MagicMock() @@ -595,6 +596,7 @@ async def test_load_protocols_no_mod_def_message_types(self): mock_mod = mock.MagicMock() mock_mod.MESSAGE_TYPES = mock.MagicMock() mock_mod.CONTROLLERS = mock.MagicMock() + mock_mod.__name__ = "test_mod" with mock.patch.object( ClassLoader, "load_module", mock.MagicMock() diff --git a/acapy_agent/protocols/issue_credential/v2_0/handlers/cred_problem_report_handler.py b/acapy_agent/protocols/issue_credential/v2_0/handlers/cred_problem_report_handler.py index b8f56f119d..f513496c79 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/handlers/cred_problem_report_handler.py +++ b/acapy_agent/protocols/issue_credential/v2_0/handlers/cred_problem_report_handler.py @@ -40,7 +40,11 @@ async def handle(self, context: RequestContext, responder: BaseResponder): context.message, context.connection_record.connection_id, ) - except (StorageError, StorageNotFoundError): + except StorageNotFoundError: + self._logger.warning( + "Record not found while processing issue-credential v2.0 problem report" + ) + except StorageError: self._logger.exception( - "Error processing issue-credential v2.0 problem report message" + "Storage error while processing issue-credential v2.0 problem report" ) diff --git a/acapy_agent/protocols/issue_credential/v2_0/routes.py b/acapy_agent/protocols/issue_credential/v2_0/routes.py index a00e0fe853..c7c73b1c35 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/routes.py +++ b/acapy_agent/protocols/issue_credential/v2_0/routes.py @@ -865,7 +865,12 @@ async def credential_exchange_send(request: web.BaseRequest): V20CredManagerError, V20CredFormatError, ) as err: - LOGGER.exception("Error preparing credential offer") + # Only log full exception for unexpected errors + if isinstance(err, (V20CredFormatError, V20CredManagerError)): + LOGGER.warning(f"Error preparing credential offer: {err.roll_up}") + else: + LOGGER.exception("Error preparing credential offer") + if cred_ex_record: async with profile.session() as session: await cred_ex_record.save_error_state(session, reason=err.roll_up) diff --git a/acapy_agent/protocols/present_proof/v2_0/handlers/pres_problem_report_handler.py b/acapy_agent/protocols/present_proof/v2_0/handlers/pres_problem_report_handler.py index be4aab8620..e10df27e2e 100644 --- a/acapy_agent/protocols/present_proof/v2_0/handlers/pres_problem_report_handler.py +++ b/acapy_agent/protocols/present_proof/v2_0/handlers/pres_problem_report_handler.py @@ -34,7 +34,11 @@ async def handle(self, context: RequestContext, responder: BaseResponder): else None ), ) - except (StorageError, StorageNotFoundError): + except StorageNotFoundError: + self._logger.warning( + "Record not found while processing present-proof v2.0 problem report" + ) + except StorageError: self._logger.exception( - "Error processing present-proof v2.0 problem report message" + "Storage error while processing present-proof v2.0 problem report" ) diff --git a/acapy_agent/transport/v2_pack_format.py b/acapy_agent/transport/v2_pack_format.py index 266c0b8b08..92e26da698 100644 --- a/acapy_agent/transport/v2_pack_format.py +++ b/acapy_agent/transport/v2_pack_format.py @@ -63,8 +63,7 @@ async def parse_message( try: message_unpack = await messaging.unpack(message_json) except CryptoServiceError: - LOGGER.debug("Message unpack failed, falling back to JSON") - print("HIT CRTYPTO SER ERR EXCEPT BLOC") + LOGGER.info("Message unpack failed, falling back to JSON") else: # Set message_dict to be the dictionary that we unpacked message_dict = message_unpack.message diff --git a/acapy_agent/utils/classloader.py b/acapy_agent/utils/classloader.py index 09d4799aea..aafcfc33ca 100644 --- a/acapy_agent/utils/classloader.py +++ b/acapy_agent/utils/classloader.py @@ -1,6 +1,7 @@ """The classloader provides utilities to dynamically load classes and modules.""" import inspect +import logging import sys from importlib import import_module, resources from importlib.util import find_spec, resolve_name @@ -9,6 +10,8 @@ from ..core.error import BaseError +LOGGER = logging.getLogger(__name__) + class ModuleLoadError(BaseError): """Module load error.""" @@ -22,7 +25,9 @@ class ClassLoader: """Class used to load classes from modules dynamically.""" @classmethod - def load_module(cls, mod_path: str, package: Optional[str] = None) -> ModuleType: + def load_module( + cls, mod_path: str, package: Optional[str] = None + ) -> Optional[ModuleType]: """Load a module by its absolute path. Args: @@ -36,6 +41,7 @@ def load_module(cls, mod_path: str, package: Optional[str] = None) -> ModuleType ModuleLoadError: If there was an error loading the module """ + if package: # preload parent package if not cls.load_module(package): @@ -45,6 +51,7 @@ def load_module(cls, mod_path: str, package: Optional[str] = None) -> ModuleType mod_path = f".{mod_path}" full_path = resolve_name(mod_path, package) + if full_path in sys.modules: return sys.modules[full_path] @@ -66,6 +73,7 @@ def load_module(cls, mod_path: str, package: Optional[str] = None) -> ModuleType try: return import_module(mod_path, package) except ModuleNotFoundError as e: + LOGGER.warning("Module %s not found during import", full_path) raise ModuleLoadError(f"Unable to import module {full_path}: {str(e)}") from e @classmethod @@ -97,23 +105,34 @@ def load_class( elif default_module: mod_path = default_module else: + LOGGER.warning( + "Cannot resolve class name %s with no default module", class_name + ) raise ClassNotFoundError( f"Cannot resolve class name with no default module: {class_name}" ) mod = cls.load_module(mod_path, package) if not mod: + LOGGER.warning( + "Module %s not found when loading class %s", mod_path, class_name + ) raise ClassNotFoundError(f"Module '{mod_path}' not found") resolved = getattr(mod, class_name, None) if not resolved: + LOGGER.warning("Class %s not found in module %s", class_name, mod_path) raise ClassNotFoundError( f"Class '{class_name}' not defined in module: {mod_path}" ) if not isinstance(resolved, type): + LOGGER.warning( + "Resolved attribute %s in module %s is not a class", class_name, mod_path + ) raise ClassNotFoundError( f"Resolved value is not a class: {mod_path}.{class_name}" ) + LOGGER.debug("Successfully loaded class %s from module %s", class_name, mod_path) return resolved @classmethod @@ -138,9 +157,14 @@ def load_subclass_of( mod = cls.load_module(mod_path, package) if not mod: + LOGGER.warning( + "Module %s not found when loading subclass of %s", + mod_path, + base_class.__name__, + ) raise ClassNotFoundError(f"Module '{mod_path}' not found") - # Find an the first declared class that inherits from + # Find the first declared class that inherits from the base_class try: imported_class = next( obj @@ -148,6 +172,11 @@ def load_subclass_of( if issubclass(obj, base_class) and obj is not base_class ) except StopIteration: + LOGGER.debug( + "No subclass of %s found in module %s", + base_class.__name__, + mod_path, + ) raise ClassNotFoundError( f"Could not resolve a class that inherits from {base_class}" ) from None @@ -156,17 +185,22 @@ def load_subclass_of( @classmethod def scan_subpackages(cls, package: str) -> Sequence[str]: """Return a list of sub-packages defined under a named package.""" + LOGGER.debug("Scanning subpackages under package %s", package) if "." in package: package, sub_pkg = package.split(".", 1) + LOGGER.debug("Extracted main package: %s, sub-package: %s", package, sub_pkg) else: sub_pkg = "." + LOGGER.debug("No sub-package provided, defaulting to %s", sub_pkg) try: package_path = resources.files(package) except FileNotFoundError: + LOGGER.warning("Package %s not found during subpackage scan", package) raise ModuleLoadError(f"Undefined package {package}") if not (package_path / sub_pkg).is_dir(): + LOGGER.warning("Sub-package %s is not a directory under %s", sub_pkg, package) raise ModuleLoadError(f"Undefined package {package}") found = [] @@ -174,7 +208,9 @@ def scan_subpackages(cls, package: str) -> Sequence[str]: sub_path = package_path / sub_pkg for item in sub_path.iterdir(): if (item / "__init__.py").exists(): - found.append(f"{package}.{joiner}{item.name}") + subpackage = f"{package}.{joiner}{item.name}" + found.append(subpackage) + LOGGER.debug("%d sub-packages found under %s: %s", len(found), package, found) return found diff --git a/acapy_agent/vc/vc_di/prove.py b/acapy_agent/vc/vc_di/prove.py index 33c94fa544..acba4359fe 100644 --- a/acapy_agent/vc/vc_di/prove.py +++ b/acapy_agent/vc/vc_di/prove.py @@ -1,6 +1,7 @@ """Verifiable Credential and Presentation proving methods.""" import asyncio +import logging import re from hashlib import sha256 from typing import Any, Optional, Tuple @@ -20,6 +21,8 @@ from ...core.profile import Profile from ..ld_proofs import LinkedDataProofException, ProofPurpose +LOGGER = logging.getLogger(__name__) + async def create_signed_anoncreds_presentation( *, @@ -311,7 +314,7 @@ async def prepare_data_for_presentation( # issuer_id = field["filter"]["const"] pass else: - print("... skipping:", path) + LOGGER.info("... skipping: %s", path) return anoncreds_proofrequest, w3c_creds_metadata diff --git a/acapy_agent/wallet/crypto.py b/acapy_agent/wallet/crypto.py index 28bf73d1f7..ed6679aae5 100644 --- a/acapy_agent/wallet/crypto.py +++ b/acapy_agent/wallet/crypto.py @@ -1,6 +1,7 @@ """Cryptography functions used by BasicWallet.""" import hashlib +import logging import re from collections import OrderedDict from typing import Callable, List, Optional, Sequence, Tuple, Union @@ -22,6 +23,8 @@ from .key_type import BLS12381G2, ED25519, KeyType from .util import b58_to_bytes, b64_to_bytes, bytes_to_b58, random_seed +LOGGER = logging.getLogger(__name__) + def create_keypair( key_type: KeyType, seed: Optional[bytes] = None @@ -432,7 +435,7 @@ def decode_pack_message_outer(enc_message: bytes) -> Tuple[dict, dict, bool]: try: wrapper = JweEnvelope.from_json(enc_message) except ValidationError as err: - print(err) + LOGGER.error(err) raise ValueError("Invalid packed message") alg = wrapper.protected.get("alg") From 3e4ece73d535168097a9f6ebb6dcbd154965f22d Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Thu, 10 Apr 2025 17:45:30 +0200 Subject: [PATCH 73/76] :bug: Fix publishing all pending AnonCreds revocations (#3626) * :art: Improve logging for `revoke_pending_credentials` Signed-off-by: ff137 * :bug: Fix `limit_crids=[]` skipping all revocations Signed-off-by: ff137 * :art: Replace unnecessary json.dumps Signed-off-by: ff137 * :test_tube: Expand test coverage Signed-off-by: ff137 --------- Signed-off-by: ff137 --- acapy_agent/anoncreds/revocation.py | 108 ++++++++++++--- .../anoncreds/tests/test_revocation.py | 129 +++++++++++++++++- 2 files changed, 210 insertions(+), 27 deletions(-) diff --git a/acapy_agent/anoncreds/revocation.py b/acapy_agent/anoncreds/revocation.py index e8cb94bcd1..251923f103 100644 --- a/acapy_agent/anoncreds/revocation.py +++ b/acapy_agent/anoncreds/revocation.py @@ -1208,6 +1208,13 @@ async def revoke_pending_credentials( Tuple with the update revocation list, list of cred rev ids not revoked """ + LOGGER.info( + "Starting revocation process for registry %s with " + "additional_crids=%s, limit_crids=%s", + revoc_reg_id, + additional_crids, + limit_crids, + ) updated_list = None failed_crids = set() max_attempt = 5 @@ -1215,12 +1222,19 @@ async def revoke_pending_credentials( while True: attempt += 1 + LOGGER.debug("Revocation attempt %d/%d", attempt, max_attempt) if attempt >= max_attempt: + LOGGER.error( + "Max attempts (%d) reached while trying to update registry %s", + max_attempt, + revoc_reg_id, + ) raise AnonCredsRevocationError( "Repeated conflict attempting to update registry" ) try: async with self.profile.session() as session: + LOGGER.debug("Fetching revocation registry data for %s", revoc_reg_id) rev_reg_def_entry = await session.handle.fetch( CATEGORY_REV_REG_DEF, revoc_reg_id ) @@ -1231,6 +1245,11 @@ async def revoke_pending_credentials( CATEGORY_REV_REG_DEF_PRIVATE, revoc_reg_id ) except AskarError as err: + LOGGER.error( + "Failed to retrieve revocation registry data for %s: %s", + revoc_reg_id, + str(err), + ) raise AnonCredsRevocationError( "Error retrieving revocation registry" ) from err @@ -1240,34 +1259,43 @@ async def revoke_pending_credentials( or not rev_list_entry or not rev_reg_def_private_entry ): + missing_data = [] + if not rev_reg_def_entry: + missing_data.append("revocation registry definition") + if not rev_list_entry: + missing_data.append("revocation list") + if not rev_reg_def_private_entry: + missing_data.append("revocation registry private definition") + LOGGER.error( + "Missing required revocation registry data for %s: %s", + revoc_reg_id, + ", ".join(missing_data), + ) raise AnonCredsRevocationError( - ( - "Missing required revocation registry data: " - "revocation registry definition" - if not rev_reg_def_entry - else "" - ), - "revocation list" if not rev_list_entry else "", - ( - "revocation registry private definition" - if not rev_reg_def_private_entry - else "" - ), + f"Missing required revocation registry data: {' '.join(missing_data)}" ) try: async with self.profile.session() as session: + cred_def_id = rev_reg_def_entry.value_json["credDefId"] + LOGGER.debug("Fetching credential definition %s", cred_def_id) cred_def_entry = await session.handle.fetch( - CATEGORY_CRED_DEF, rev_reg_def_entry.value_json["credDefId"] + CATEGORY_CRED_DEF, cred_def_id ) except AskarError as err: + LOGGER.error( + "Failed to retrieve credential definition %s: %s", + cred_def_id, + str(err), + ) raise AnonCredsRevocationError( - f"Error retrieving cred def {rev_reg_def_entry.value_json['credDefId']}" # noqa: E501 + f"Error retrieving cred def {cred_def_id}" ) from err try: # TODO This is a little rough; stored tails location will have public uri # but library needs local tails location + LOGGER.debug("Deserializing revocation registry data") rev_reg_def = RevRegDef.deserialize(rev_reg_def_entry.value_json) rev_reg_def.value.tails_location = self.get_local_tails_path(rev_reg_def) cred_def = CredDef.deserialize(cred_def_entry.value_json) @@ -1275,6 +1303,9 @@ async def revoke_pending_credentials( rev_reg_def_private_entry.value_json ) except AnoncredsError as err: + LOGGER.error( + "Failed to load revocation registry definition: %s", str(err) + ) raise AnonCredsRevocationError( "Error loading revocation registry definition" ) from err @@ -1286,21 +1317,29 @@ async def revoke_pending_credentials( cred_revoc_ids = (rev_info["pending"] or []) + (additional_crids or []) rev_list = RevList.deserialize(rev_info["rev_list"]) + LOGGER.info( + "Processing %d credential revocation IDs for registry %s", + len(cred_revoc_ids), + revoc_reg_id, + ) + for rev_id in cred_revoc_ids: if rev_id < 1 or rev_id > max_cred_num: LOGGER.error( "Skipping requested credential revocation " - "on rev reg id %s, cred rev id=%s not in range", + "on rev reg id %s, cred rev id=%s not in range (1-%d)", revoc_reg_id, rev_id, + max_cred_num, ) failed_crids.add(rev_id) elif rev_id >= rev_info["next_index"]: LOGGER.warning( "Skipping requested credential revocation " - "on rev reg id %s, cred rev id=%s not yet issued", + "on rev reg id %s, cred rev id=%s not yet issued (next_index=%d)", revoc_reg_id, rev_id, + rev_info["next_index"], ) failed_crids.add(rev_id) elif rev_list.revocation_list[rev_id] == 1: @@ -1315,15 +1354,26 @@ async def revoke_pending_credentials( rev_crids.add(rev_id) if not rev_crids: + LOGGER.info( + "No valid credentials to revoke for registry %s", revoc_reg_id + ) break - if limit_crids is None: + if limit_crids is None or limit_crids == []: skipped_crids = set() else: skipped_crids = rev_crids - set(limit_crids) rev_crids = rev_crids - skipped_crids + LOGGER.info( + "Revoking %d credentials, skipping %d credentials for registry %s", + len(rev_crids), + len(skipped_crids), + revoc_reg_id, + ) + try: + LOGGER.debug("Updating revocation list with new revocations") updated_list = await asyncio.get_event_loop().run_in_executor( None, lambda: rev_list.to_native().update( @@ -1336,25 +1386,31 @@ async def revoke_pending_credentials( ), ) except AnoncredsError as err: + LOGGER.error("Failed to update revocation registry: %s", str(err)) raise AnonCredsRevocationError( "Error updating revocation registry" ) from err try: async with self.profile.transaction() as txn: + LOGGER.debug("Saving updated revocation list") rev_info_upd = await txn.handle.fetch( CATEGORY_REV_LIST, revoc_reg_id, for_update=True ) if not rev_info_upd: LOGGER.warning( - f"Revocation registry missing, skipping update: {revoc_reg_id}" # noqa: E501 + "Revocation registry %s missing during update, skipping", + revoc_reg_id, ) updated_list = None break tags = rev_info_upd.tags rev_info_upd = rev_info_upd.value_json if rev_info_upd != rev_info: - # handle concurrent update to the registry by retrying + LOGGER.debug( + "Concurrent update detected for registry %s, retrying", + revoc_reg_id, + ) continue rev_info_upd["rev_list"] = updated_list.to_dict() rev_info_upd["pending"] = ( @@ -1368,18 +1424,30 @@ async def revoke_pending_credentials( tags=tags, ) await txn.commit() + LOGGER.info( + "Successfully updated revocation list for registry %s", + revoc_reg_id, + ) except AskarError as err: + LOGGER.error("Failed to save revocation registry: %s", str(err)) raise AnonCredsRevocationError( "Error saving revocation registry" ) from err break - return RevokeResult( + result = RevokeResult( prev=rev_list, curr=RevList.from_native(updated_list) if updated_list else None, revoked=list(rev_crids), failed=[str(rev_id) for rev_id in sorted(failed_crids)], ) + LOGGER.info( + "Completed revocation process for registry %s: %d revoked, %d failed", + revoc_reg_id, + len(result.revoked), + len(result.failed), + ) + return result async def mark_pending_revocations(self, rev_reg_def_id: str, *crids: int): """Cred rev ids stored to publish later.""" diff --git a/acapy_agent/anoncreds/tests/test_revocation.py b/acapy_agent/anoncreds/tests/test_revocation.py index f56d552dde..db3013fc35 100644 --- a/acapy_agent/anoncreds/tests/test_revocation.py +++ b/acapy_agent/anoncreds/tests/test_revocation.py @@ -1,10 +1,11 @@ import http -import json import os from unittest import IsolatedAsyncioTestCase import pytest from anoncreds import ( + AnoncredsError, + AnoncredsErrorCode, Credential, CredentialDefinition, RevocationRegistryDefinition, @@ -1220,15 +1221,15 @@ async def test_revoke_pending_credentials( AskarError(code=AskarErrorCode.UNEXPECTED, message="test"), # missing rev reg def None, - MockEntry(value_json=json.dumps({})), - MockEntry(value_json=json.dumps({})), + MockEntry(value_json="{}"), + MockEntry(value_json="{}"), # missing rev list - MockEntry(value_json=json.dumps({})), + MockEntry(value_json="{}"), None, - MockEntry(value_json=json.dumps({})), + MockEntry(value_json="{}"), # missing rev private - MockEntry(value_json=json.dumps({})), - MockEntry(value_json=json.dumps({})), + MockEntry(value_json="{}"), + MockEntry(value_json="{}"), None, ] ) @@ -1297,6 +1298,120 @@ async def test_revoke_pending_credentials( assert mock_deserialize_cred_def.called assert isinstance(result, test_module.RevokeResult) + @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(RevList, "to_native") + @mock.patch.object(RevList, "from_native", return_value=None) + @mock.patch.object(RevRegDef, "to_native") + @mock.patch.object(CredDef, "deserialize") + @mock.patch.object(RevocationRegistryDefinitionPrivate, "load") + async def test_revoke_pending_credentials_cred_def_error( + self, + mock_load_rev_reg, + mock_deserialize_cred_def, + mock_rev_reg_to_native, + mock_rev_list_from_native, + mock_rev_list_to_native, + mock_handle, + ): + """Test error handling when fetching credential definition fails.""" + mock_handle.fetch = mock.CoroutineMock( + side_effect=[ + MockEntry(value_json=MOCK_REV_REG_DEF), + MockEntry( + value_json={ + "pending": [0, 1, 4, 3], + "next_index": 4, + "rev_list": rev_list.serialize(), + } + ), + MockEntry(), + AskarError(code=AskarErrorCode.UNEXPECTED, message="test error"), + ] + ) + + with self.assertRaises(test_module.AnonCredsRevocationError) as cm: + await self.revocation.revoke_pending_credentials( + revoc_reg_id="test-rev-reg-id", + ) + assert "Error retrieving cred def" in str(cm.exception) + + @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(RevList, "to_native") + @mock.patch.object(RevList, "from_native", return_value=None) + @mock.patch.object(RevRegDef, "to_native") + @mock.patch.object(CredDef, "deserialize") + @mock.patch.object(RevocationRegistryDefinitionPrivate, "load") + async def test_revoke_pending_credentials_anoncreds_error( + self, + mock_load_rev_reg, + mock_deserialize_cred_def, + mock_rev_reg_to_native, + mock_rev_list_from_native, + mock_rev_list_to_native, + mock_handle, + ): + """Test error handling when loading revocation registry definition fails.""" + mock_handle.fetch = mock.CoroutineMock( + side_effect=[ + MockEntry(value_json=MOCK_REV_REG_DEF), + MockEntry( + value_json={ + "pending": [0, 1, 4, 3], + "next_index": 4, + "rev_list": rev_list.serialize(), + } + ), + MockEntry(), + MockEntry(), + ] + ) + mock_deserialize_cred_def.side_effect = AnoncredsError( + AnoncredsErrorCode.UNEXPECTED, "Failed to load" + ) + + with self.assertRaises(test_module.AnonCredsRevocationError) as cm: + await self.revocation.revoke_pending_credentials( + revoc_reg_id="test-rev-reg-id", + ) + assert "Error loading revocation registry definition" in str(cm.exception) + + @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(RevList, "to_native") + @mock.patch.object(RevList, "from_native", return_value=None) + @mock.patch.object(RevRegDef, "to_native") + @mock.patch.object(CredDef, "deserialize") + @mock.patch.object(RevocationRegistryDefinitionPrivate, "load") + async def test_revoke_pending_credentials_no_valid_credentials( + self, + mock_load_rev_reg, + mock_deserialize_cred_def, + mock_rev_reg_to_native, + mock_rev_list_from_native, + mock_rev_list_to_native, + mock_handle, + ): + """Test handling when there are no valid credentials to revoke.""" + mock_handle.fetch = mock.CoroutineMock( + side_effect=[ + MockEntry(value_json=MOCK_REV_REG_DEF), + MockEntry( + value_json={ + "pending": [], # No pending revocations + "next_index": 4, + "rev_list": rev_list.serialize(), + } + ), + MockEntry(), + MockEntry(), + ] + ) + + result = await self.revocation.revoke_pending_credentials( + revoc_reg_id="test-rev-reg-id", + ) + assert result.revoked == [] # No credentials were revoked + assert result.failed == [] # No failures + @mock.patch.object(AskarAnoncredsProfileSession, "handle") async def test_mark_pending_revocations(self, mock_handle): mock_handle.fetch = mock.CoroutineMock( From 3caf68058769912741d685dfe9c57f1ed1f375c4 Mon Sep 17 00:00:00 2001 From: George Mulhearn <57472912+gmulhearn@users.noreply.github.com> Date: Fri, 11 Apr 2025 15:54:41 +1000 Subject: [PATCH 74/76] Add BLS12381G2 keys to multikey manager (#3640) --- acapy_agent/wallet/keys/manager.py | 13 ++++++++++++- .../wallet/keys/tests/test_key_operations.py | 6 ++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/acapy_agent/wallet/keys/manager.py b/acapy_agent/wallet/keys/manager.py index bab88b3dcb..a7ca3595a6 100644 --- a/acapy_agent/wallet/keys/manager.py +++ b/acapy_agent/wallet/keys/manager.py @@ -2,7 +2,7 @@ from ...core.profile import ProfileSession from ..base import BaseWallet -from ..key_type import ED25519, P256, KeyType +from ..key_type import BLS12381G2, ED25519, P256, KeyType from ..util import b58_to_bytes, bytes_to_b58 from ...utils.multiformats import multibase from ...wallet.error import WalletNotFoundError @@ -22,6 +22,12 @@ "prefix_hex": "8024", "prefix_length": 2, }, + "bls12381g2": { + "key_type": BLS12381G2, + "multikey_prefix": "zUC7", + "prefix_hex": "eb01", + "prefix_length": 2, + }, } @@ -84,6 +90,11 @@ async def resolve_multikey_from_verification_method(self, kid: str): elif verification_method.type == "Ed25519VerificationKey2020": multikey = verification_method.public_key_multibase + elif verification_method.type == "Bls12381G2Key2020": + multikey = verkey_to_multikey( + verification_method.public_key_base58, alg="bls12381g2" + ) + else: raise MultikeyManagerError("Unknown verification method type.") diff --git a/acapy_agent/wallet/keys/tests/test_key_operations.py b/acapy_agent/wallet/keys/tests/test_key_operations.py index 6ec4264f66..8bbee4aa71 100644 --- a/acapy_agent/wallet/keys/tests/test_key_operations.py +++ b/acapy_agent/wallet/keys/tests/test_key_operations.py @@ -22,6 +22,10 @@ class TestKeyOperations(IsolatedAsyncioTestCase): p256_verkey = "demmi97mhJ7JQu31git4hQz8a1PD1dETJH9TVKaynNQv" p256_alg = "p256" + bls12381g2_multikey = "zUC71fcKNvfU5d4NT3vurh8wdBqD2VSaVz7RdHmsfFBiYqfLDFkJTVK3m3hLb7yYDZq1C95HyssoX5BCr4ZatwP7jEh3UnwW7AMnx5fxdrhNkGVknbVY5QmjJ6S2CmtztCCffFL" + bls12381g2_verkey = "mq4SKF1Ej1CA37G4gkSjKtUHnD8NU1ZVkuC4BPiuoxJXoenfkputxbjfS8dHhGHN3vfQwU1z9BdEuBqTjg3PuHAKgT3Q9XEJgRyZje4WGKMtRh9vzUbd8J23jbA7Je3oAe2" + bls12381g2_alg = "bls12381g2" + async def asyncSetUp(self) -> None: self.profile = await create_test_profile() self.profile.context.injector.bind_instance(KeyTypes, KeyTypes()) @@ -32,6 +36,7 @@ async def test_key_creation(self): [ (self.ed25519_alg, self.ed25519_multikey), (self.p256_alg, self.p256_multikey), + (self.bls12381g2_alg, self.bls12381g2_multikey), ] ): kid = f"did:web:example.com#key-0{i}" @@ -62,6 +67,7 @@ async def test_key_transformations(self): for alg, multikey, verkey in [ (self.ed25519_alg, self.ed25519_multikey, self.ed25519_verkey), (self.p256_alg, self.p256_multikey, self.p256_verkey), + (self.bls12381g2_alg, self.bls12381g2_multikey, self.bls12381g2_verkey), ]: assert multikey_to_verkey(multikey) == verkey assert verkey_to_multikey(verkey, alg=alg) == multikey From 609be86131c41ad2741f181306acec678df8f0a5 Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Sun, 13 Apr 2025 12:23:06 +0200 Subject: [PATCH 75/76] :art: Rename Anoncreds to AnonCreds (#3573) * :art: Rename Anoncreds to AnonCreds Signed-off-by: ff137 * :art: Organize imports Signed-off-by: ff137 * :art: Rename Anoncreds to AnonCreds in docs and other files Signed-off-by: ff137 * :art: Fix AnoncredsError Signed-off-by: ff137 * :art: Rename AnonCreds in swagger titles Signed-off-by: ff137 * :art: Include additional renames Signed-off-by: ff137 * :memo: Updated openapi specs Signed-off-by: ff137 * :rewind: Revert renaming owl-agent-test-harness tag Signed-off-by: ff137 --------- Signed-off-by: ff137 --- .github/workflows/bdd-interop-tests.yml | 2 +- Managing-ACA-Py-Doc-Site.md | 2 +- acapy_agent/admin/server.py | 2 +- acapy_agent/admin/tests/test_admin_server.py | 2 +- acapy_agent/anoncreds/base.py | 6 +- .../anoncreds/default/did_indy/registry.py | 4 +- .../anoncreds/default/did_web/registry.py | 4 +- .../anoncreds/default/legacy_indy/author.py | 4 +- .../anoncreds/default/legacy_indy/registry.py | 13 +- .../legacy_indy/tests/test_registry.py | 12 +- acapy_agent/anoncreds/error_messages.py | 2 +- acapy_agent/anoncreds/holder.py | 22 +- acapy_agent/anoncreds/issuer.py | 8 +- acapy_agent/anoncreds/models/credential.py | 44 +-- .../anoncreds/models/credential_definition.py | 20 +- .../anoncreds/models/credential_offer.py | 36 +-- .../anoncreds/models/credential_proposal.py | 6 +- .../anoncreds/models/credential_request.py | 16 +- .../anoncreds/models/non_rev_interval.py | 14 +- .../anoncreds/models/presentation_request.py | 26 +- acapy_agent/anoncreds/models/proof.py | 296 +++++++++--------- .../anoncreds/models/requested_credentials.py | 4 +- acapy_agent/anoncreds/models/revocation.py | 2 +- acapy_agent/anoncreds/models/schema.py | 7 +- acapy_agent/anoncreds/models/schema_info.py | 2 +- acapy_agent/anoncreds/registry.py | 4 +- acapy_agent/anoncreds/revocation.py | 12 +- acapy_agent/anoncreds/routes.py | 20 +- acapy_agent/anoncreds/tests/test_holder.py | 31 +- acapy_agent/anoncreds/tests/test_issuer.py | 54 ++-- .../anoncreds/tests/test_revocation.py | 56 ++-- acapy_agent/anoncreds/tests/test_routes.py | 8 +- acapy_agent/anoncreds/tests/test_verifier.py | 5 +- acapy_agent/anoncreds/verifier.py | 2 +- acapy_agent/askar/profile_anon.py | 20 +- acapy_agent/commands/tests/test_provision.py | 4 +- acapy_agent/config/logging/__init__.py | 2 +- acapy_agent/connections/base_manager.py | 8 +- .../connections/tests/test_base_manager.py | 4 +- acapy_agent/connections/tests/test_routes.py | 2 +- acapy_agent/did/did_key.py | 1 + acapy_agent/didcomm_v2/tests/test_adapters.py | 4 +- acapy_agent/holder/tests/test_routes.py | 2 +- acapy_agent/indy/credx/holder.py | 2 +- .../indy/credx/tests/test_cred_issuance.py | 4 +- .../indy/models/tests/test_pres_preview.py | 4 +- acapy_agent/indy/tests/test_verifier.py | 4 +- acapy_agent/ledger/base.py | 4 +- .../multiple_ledger/indy_vdr_manager.py | 5 +- acapy_agent/ledger/tests/test_routes.py | 10 +- .../tests/test_routes.py | 4 +- .../messaging/schemas/tests/test_routes.py | 4 +- acapy_agent/messaging/valid.py | 30 +- acapy_agent/multitenant/manager.py | 4 +- acapy_agent/multitenant/route_manager.py | 4 +- .../single_wallet_askar_manager.py | 4 +- .../multitenant/tests/test_route_manager.py | 4 +- .../tests/test_single_wallet_askar_manager.py | 8 +- .../v1_0/messages/basicmessage.py | 5 +- .../v1_0/messages/keylist.py | 5 +- .../v1_0/messages/keylist_query.py | 5 +- .../v1_0/route_manager_provider.py | 5 +- .../coordinate_mediation/v1_0/routes.py | 7 +- .../protocols/did_rotate/v1_0/manager.py | 5 +- .../v1_0/messages/problem_report.py | 5 +- .../protocols/didexchange/v1_0/manager.py | 5 +- .../protocols/discovery/v1_0/routes.py | 5 +- .../protocols/discovery/v2_0/routes.py | 5 +- .../tests/test_forward_invitation_handler.py | 2 +- .../handlers/tests/test_invitation_handler.py | 2 +- .../tests/test_invitation_request_handler.py | 4 +- .../protocols/issue_credential/v1_0/routes.py | 10 +- .../v2_0/formats/anoncreds/handler.py | 34 +- .../formats/anoncreds/tests/test_handler.py | 36 +-- .../v2_0/formats/indy/handler.py | 4 +- .../formats/ld_proof/tests/test_handler.py | 2 +- .../v2_0/formats/vc_di/handler.py | 8 +- .../v2_0/formats/vc_di/models/cred_offer.py | 22 +- .../v2_0/formats/vc_di/models/cred_request.py | 8 +- .../v2_0/formats/vc_di/tests/test_handler.py | 32 +- .../v2_0/messages/cred_format.py | 6 +- .../v2_0/models/detail/anoncreds.py | 14 +- .../protocols/issue_credential/v2_0/routes.py | 6 +- .../v2_0/tests/test_routes.py | 4 +- .../protocols/out_of_band/v1_0/manager.py | 2 +- .../out_of_band/v1_0/tests/test_manager.py | 12 +- .../anoncreds/pres_exch_handler.py | 8 +- .../present_proof/dif/pres_exch_handler.py | 2 +- .../v1_0/models/presentation_exchange.py | 5 +- .../present_proof/v1_0/tests/test_routes.py | 4 +- .../v2_0/formats/anoncreds/handler.py | 19 +- .../present_proof/v2_0/formats/dif/handler.py | 9 +- .../v2_0/formats/indy/handler.py | 7 +- .../protocols/present_proof/v2_0/routes.py | 17 +- .../present_proof/v2_0/tests/test_manager.py | 7 +- .../v2_0/tests/test_manager_anoncreds.py | 27 +- .../present_proof/v2_0/tests/test_routes.py | 4 +- .../v2_0/tests/test_routes_anoncreds.py | 10 +- .../routing/v1_0/handlers/forward_handler.py | 2 +- acapy_agent/resolver/default/peer4.py | 8 +- .../resolver/default/tests/test_indy.py | 4 +- acapy_agent/revocation/manager.py | 4 +- acapy_agent/revocation/routes.py | 5 +- acapy_agent/revocation/tests/test_indy.py | 4 +- acapy_agent/revocation/tests/test_manager.py | 4 +- .../models/issuer_cred_rev_record.py | 4 +- acapy_agent/revocation_anoncreds/routes.py | 66 ++-- .../tests/test_manager.py | 22 +- .../revocation_anoncreds/tests/test_routes.py | 2 +- acapy_agent/utils/profiles.py | 6 +- acapy_agent/utils/testing.py | 6 +- .../cryptosuites/eddsa_jcs_2022.py | 15 +- acapy_agent/vc/data_integrity/manager.py | 10 +- .../vc/data_integrity/models/__init__.py | 4 +- .../vc/data_integrity/models/options.py | 6 +- acapy_agent/vc/data_integrity/models/proof.py | 6 +- .../models/verification_response.py | 2 +- acapy_agent/vc/data_integrity/routes.py | 5 +- acapy_agent/vc/ld_proofs/__init__.py | 2 +- .../vc/ld_proofs/crypto/wallet_key_pair.py | 3 +- acapy_agent/vc/ld_proofs/suites/__init__.py | 4 +- .../tests/test_document_downloader.py | 4 +- acapy_agent/vc/tests/contexts/__init__.py | 2 +- acapy_agent/vc/tests/data/__init__.py | 4 +- acapy_agent/vc/tests/document_loader.py | 4 +- .../vc/vc_ld/models/tests/test_credential.py | 5 +- acapy_agent/vc/vc_ld/tests/test_manager.py | 6 +- acapy_agent/vc/vc_ld/tests/test_vc_ld.py | 9 +- acapy_agent/vc/vc_ld/tests/test_vc_v2.py | 13 +- acapy_agent/wallet/anoncreds_upgrade.py | 8 +- .../default_verification_key_strategy.py | 2 +- acapy_agent/wallet/keys/manager.py | 6 +- acapy_agent/wallet/keys/routes.py | 2 +- acapy_agent/wallet/routes.py | 4 +- acapy_agent/wallet/singletons.py | 2 +- .../wallet/tests/test_anoncreds_upgrade.py | 2 +- .../test_default_verification_key_strategy.py | 7 +- conftest.py | 6 +- demo/features/revocation-api.feature | 2 +- demo/features/upgrade.feature | 2 +- demo/runners/faber.py | 2 +- ...bility.md => AnonCredsW3CCompatibility.md} | 0 docs/design/UpgradeViaApi.md | 4 +- ...idation.md => AnonCredsProofValidation.md} | 2 +- mkdocs.yml | 4 +- open-api/openapi.json | 254 ++++++++------- open-api/swagger.json | 237 +++++++------- .../docker-compose.yml | 2 +- .../example.py | 22 +- scenarios/examples/mediation/example.py | 6 +- .../restart_anoncreds_upgrade/example.py | 6 +- scenarios/examples/simple_restart/example.py | 4 +- scenarios/examples/util.py | 10 +- 153 files changed, 979 insertions(+), 1127 deletions(-) rename docs/design/{AnoncredsW3CCompatibility.md => AnonCredsW3CCompatibility.md} (100%) rename docs/features/{AnoncredsProofValidation.md => AnonCredsProofValidation.md} (99%) diff --git a/.github/workflows/bdd-interop-tests.yml b/.github/workflows/bdd-interop-tests.yml index a70a03ea4c..c3758d004c 100644 --- a/.github/workflows/bdd-interop-tests.yml +++ b/.github/workflows/bdd-interop-tests.yml @@ -84,7 +84,7 @@ jobs: run: | cd owl-agent-test-harness NO_TTY=1 LEDGER_URL_CONFIG=http://test.bcovrin.vonx.io TAILS_SERVER_URL_CONFIG=https://tails.vonx.io ./manage run -d acapy-main -t @critical -t ~@wip -t ~@T004-RFC0211 -t ~@DidMethod_orb -t ~@Transport_NoHttpOutbound -t ~@Anoncreds >> output.txt - - name: Run Release or Nightly Interop Tests Anoncreds + - name: Run Release or Nightly Interop Tests AnonCreds if: (steps.check_if_release.outputs.is_release == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' && steps.check-if-src-changed.outputs.run_tests != 'false') run: | cd owl-agent-test-harness diff --git a/Managing-ACA-Py-Doc-Site.md b/Managing-ACA-Py-Doc-Site.md index ed9722d102..db30a8db1b 100644 --- a/Managing-ACA-Py-Doc-Site.md +++ b/Managing-ACA-Py-Doc-Site.md @@ -67,7 +67,7 @@ are a few files listed below that we don't generate into the documentation site, and they can be ignored. - `assets/README.md` -- `design/AnoncredsW3CCompatibility.md` +- `design/AnonCredsW3CCompatibility.md` - `design/UpgradeViaApi.md` - `features/W3cCredentials.md` diff --git a/acapy_agent/admin/server.py b/acapy_agent/admin/server.py index fa32df503f..3f7d814620 100644 --- a/acapy_agent/admin/server.py +++ b/acapy_agent/admin/server.py @@ -65,7 +65,7 @@ "acapy::keylist::updated": "keylist", } -anoncreds_wallets = singletons.IsAnoncredsSingleton().wallets +anoncreds_wallets = singletons.IsAnonCredsSingleton().wallets in_progress_upgrades = singletons.UpgradeInProgressSingleton() status_paths = ("/status/live", "/status/ready") diff --git a/acapy_agent/admin/tests/test_admin_server.py b/acapy_agent/admin/tests/test_admin_server.py index 8c8a8e8039..52aad61761 100644 --- a/acapy_agent/admin/tests/test_admin_server.py +++ b/acapy_agent/admin/tests/test_admin_server.py @@ -567,7 +567,7 @@ async def test_upgrade_middleware(self): await storage.delete_record(upgrading_record) # Upgrade in progress with cache - singletons.IsAnoncredsSingleton().set_wallet(profile.name) + singletons.IsAnonCredsSingleton().set_wallet(profile.name) await test_module.upgrade_middleware(request, handler) diff --git a/acapy_agent/anoncreds/base.py b/acapy_agent/anoncreds/base.py index 9163d8d431..a1e4cd7a85 100644 --- a/acapy_agent/anoncreds/base.py +++ b/acapy_agent/anoncreds/base.py @@ -16,7 +16,7 @@ RevRegDefResult, ) from .models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult -from .models.schema_info import AnoncredsSchemaInfo +from .models.schema_info import AnonCredsSchemaInfo T = TypeVar("T") @@ -138,12 +138,12 @@ async def get_revocation_list( @abstractmethod async def get_schema_info_by_id( self, profile: Profile, schema_id: str - ) -> AnoncredsSchemaInfo: + ) -> AnonCredsSchemaInfo: """Get a schema info from the registry.""" class BaseAnonCredsRegistrar(BaseAnonCredsHandler): - """Base Anoncreds Registrar.""" + """Base AnonCreds Registrar.""" @abstractmethod async def register_schema( diff --git a/acapy_agent/anoncreds/default/did_indy/registry.py b/acapy_agent/anoncreds/default/did_indy/registry.py index 0234196571..23c6d6e014 100644 --- a/acapy_agent/anoncreds/default/did_indy/registry.py +++ b/acapy_agent/anoncreds/default/did_indy/registry.py @@ -17,7 +17,7 @@ RevRegDefResult, ) from ...models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult -from ...models.schema_info import AnoncredsSchemaInfo +from ...models.schema_info import AnonCredsSchemaInfo LOGGER = logging.getLogger(__name__) @@ -122,6 +122,6 @@ async def update_revocation_list( async def get_schema_info_by_id( self, profile: Profile, schema_id: str - ) -> AnoncredsSchemaInfo: + ) -> AnonCredsSchemaInfo: """Get a schema info from the registry.""" return await super().get_schema_info_by_id(schema_id) diff --git a/acapy_agent/anoncreds/default/did_web/registry.py b/acapy_agent/anoncreds/default/did_web/registry.py index 3f2535cc7a..5a432096ab 100644 --- a/acapy_agent/anoncreds/default/did_web/registry.py +++ b/acapy_agent/anoncreds/default/did_web/registry.py @@ -17,7 +17,7 @@ RevRegDefResult, ) from ...models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult -from ...models.schema_info import AnoncredsSchemaInfo +from ...models.schema_info import AnonCredsSchemaInfo LOGGER = logging.getLogger(__name__) @@ -124,6 +124,6 @@ async def update_revocation_list( async def get_schema_info_by_id( self, profile: Profile, schema_id: str - ) -> AnoncredsSchemaInfo: + ) -> AnonCredsSchemaInfo: """Get a schema info from the registry.""" return await super().get_schema_info_by_id(schema_id) diff --git a/acapy_agent/anoncreds/default/legacy_indy/author.py b/acapy_agent/anoncreds/default/legacy_indy/author.py index 1d6839caa9..dc8bd829a7 100644 --- a/acapy_agent/anoncreds/default/legacy_indy/author.py +++ b/acapy_agent/anoncreds/default/legacy_indy/author.py @@ -6,9 +6,7 @@ from acapy_agent.connections.models.conn_record import ConnRecord from acapy_agent.messaging.models.base import BaseModelError -from acapy_agent.protocols.endorse_transaction.v1_0.util import ( - get_endorser_connection_id, -) +from acapy_agent.protocols.endorse_transaction.v1_0.util import get_endorser_connection_id from acapy_agent.storage.error import StorageNotFoundError diff --git a/acapy_agent/anoncreds/default/legacy_indy/registry.py b/acapy_agent/anoncreds/default/legacy_indy/registry.py index 950ce434a6..5e41d3a263 100644 --- a/acapy_agent/anoncreds/default/legacy_indy/registry.py +++ b/acapy_agent/anoncreds/default/legacy_indy/registry.py @@ -74,13 +74,8 @@ RevRegDefState, RevRegDefValue, ) -from ...models.schema import ( - AnonCredsSchema, - GetSchemaResult, - SchemaResult, - SchemaState, -) -from ...models.schema_info import AnoncredsSchemaInfo +from ...models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult, SchemaState +from ...models.schema_info import AnonCredsSchemaInfo from ...revocation import ( CATEGORY_REV_LIST, CATEGORY_REV_REG_DEF, @@ -1233,10 +1228,10 @@ async def txn_submit( async def get_schema_info_by_id( self, profile: Profile, schema_id: str - ) -> AnoncredsSchemaInfo: + ) -> AnonCredsSchemaInfo: """Get schema info by schema id.""" schema_id_parts = re.match(r"^(\w+):2:([^:]+):([^:]+)$", schema_id) - return AnoncredsSchemaInfo( + return AnonCredsSchemaInfo( issuer_id=schema_id_parts.group(1), name=schema_id_parts.group(2), version=schema_id_parts.group(3), diff --git a/acapy_agent/anoncreds/default/legacy_indy/tests/test_registry.py b/acapy_agent/anoncreds/default/legacy_indy/tests/test_registry.py index 76ebbee7a2..bed2097a59 100644 --- a/acapy_agent/anoncreds/default/legacy_indy/tests/test_registry.py +++ b/acapy_agent/anoncreds/default/legacy_indy/tests/test_registry.py @@ -16,9 +16,7 @@ from .....anoncreds.base import AnonCredsSchemaAlreadyExists from .....anoncreds.default.legacy_indy import registry as test_module from .....anoncreds.issuer import AnonCredsIssuer -from .....askar.profile_anon import ( - AskarAnoncredsProfileSession, -) +from .....askar.profile_anon import AskarAnonCredsProfileSession from .....connections.models.conn_record import ConnRecord from .....core.event_bus import EventBus from .....ledger.base import BaseLedger @@ -31,9 +29,7 @@ from .....protocols.endorse_transaction.v1_0.models.transaction_record import ( TransactionRecord, ) -from .....revocation_anoncreds.models.issuer_cred_rev_record import ( - IssuerCredRevRecord, -) +from .....revocation_anoncreds.models.issuer_cred_rev_record import IssuerCredRevRecord from .....tests import mock from .....utils.testing import create_test_profile from ....models.credential_definition import ( @@ -800,7 +796,7 @@ async def test_txn_submit(self): ), ), ) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_register_revocation_list_no_endorsement( self, mock_handle, mock_send_revoc_reg_entry ): @@ -1165,7 +1161,7 @@ async def test_fix_ledger_entry(self, *_): update=mock.MagicMock(return_value=MockRevListEntry()) ), ) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_sync_wallet_rev_list_with_issuer_cred_rev_records( self, mock_handle, *_ ): diff --git a/acapy_agent/anoncreds/error_messages.py b/acapy_agent/anoncreds/error_messages.py index 8ec6fc5477..4118335526 100644 --- a/acapy_agent/anoncreds/error_messages.py +++ b/acapy_agent/anoncreds/error_messages.py @@ -1,3 +1,3 @@ """Error messages for anoncreds.""" -ANONCREDS_PROFILE_REQUIRED_MSG = "AnonCreds interface requires AskarAnoncreds profile" +ANONCREDS_PROFILE_REQUIRED_MSG = "AnonCreds interface requires AskarAnonCreds profile" diff --git a/acapy_agent/anoncreds/holder.py b/acapy_agent/anoncreds/holder.py index e6cbedf37c..79f2e58754 100644 --- a/acapy_agent/anoncreds/holder.py +++ b/acapy_agent/anoncreds/holder.py @@ -1,4 +1,4 @@ -"""Anoncreds holder implementation.""" +"""AnonCreds holder implementation.""" import asyncio import json @@ -22,7 +22,7 @@ from pyld.jsonld import JsonLdProcessor from uuid_utils import uuid4 -from ..askar.profile_anon import AskarAnoncredsProfile +from ..askar.profile_anon import AskarAnonCredsProfile from ..core.error import BaseError from ..core.profile import Profile from ..storage.vc_holder.base import VCHolder @@ -78,9 +78,9 @@ def __init__(self, profile: Profile): self._profile = profile @property - def profile(self) -> AskarAnoncredsProfile: + def profile(self) -> AskarAnonCredsProfile: """Accessor for the profile instance.""" - if not isinstance(self._profile, AskarAnoncredsProfile): + if not isinstance(self._profile, AskarAnonCredsProfile): raise ValueError(ANONCREDS_PROFILE_REQUIRED_MSG) return self._profile @@ -598,10 +598,10 @@ async def create_presentation( Args: presentation_request: Valid indy format presentation request - requested_credentials: Anoncreds format requested credentials - schemas: Anoncreds formatted schemas JSON - credential_definitions: Anoncreds formatted credential definitions JSON - rev_states: Anoncreds format revocation states JSON + requested_credentials: AnonCreds format requested credentials + schemas: AnonCreds formatted schemas JSON + credential_definitions: AnonCreds formatted credential definitions JSON + rev_states: AnonCreds format revocation states JSON """ @@ -691,9 +691,9 @@ async def create_presentation_w3c( presentation_request: Valid indy format presentation request requested_credentials_w3c: W3C format requested credentials credentials_w3c_metadata: W3C format credential metadata - schemas: Anoncreds formatted schemas JSON - credential_definitions: Anoncreds formatted credential definitions JSON - rev_states: Anoncreds format revocation states JSON + schemas: AnonCreds formatted schemas JSON + credential_definitions: AnonCreds formatted credential definitions JSON + rev_states: AnonCreds format revocation states JSON """ present_creds = PresentCredentials() diff --git a/acapy_agent/anoncreds/issuer.py b/acapy_agent/anoncreds/issuer.py index 2bfd1cb490..7f7e7b93a1 100644 --- a/acapy_agent/anoncreds/issuer.py +++ b/acapy_agent/anoncreds/issuer.py @@ -17,7 +17,7 @@ ) from aries_askar import AskarError -from ..askar.profile_anon import AskarAnoncredsProfile, AskarAnoncredsProfileSession +from ..askar.profile_anon import AskarAnonCredsProfile, AskarAnonCredsProfileSession from ..core.error import BaseError from ..core.event_bus import Event, EventBus from ..core.profile import Profile @@ -91,9 +91,9 @@ def __init__(self, profile: Profile): self._profile = profile @property - def profile(self) -> AskarAnoncredsProfile: + def profile(self) -> AskarAnonCredsProfile: """Accessor for the profile instance.""" - if not isinstance(self._profile, AskarAnoncredsProfile): + if not isinstance(self._profile, AskarAnonCredsProfile): raise ValueError(ANONCREDS_PROFILE_REQUIRED_MSG) return self._profile @@ -105,7 +105,7 @@ async def notify(self, event: Event): async def _finish_registration( self, - txn: AskarAnoncredsProfileSession, + txn: AskarAnonCredsProfileSession, category: str, job_id: str, registered_id: str, diff --git a/acapy_agent/anoncreds/models/credential.py b/acapy_agent/anoncreds/models/credential.py index c008fc16c7..1b5d3063cd 100644 --- a/acapy_agent/anoncreds/models/credential.py +++ b/acapy_agent/anoncreds/models/credential.py @@ -17,13 +17,13 @@ ) -class AnoncredsAttrValue(BaseModel): - """Anoncreds attribute value.""" +class AnonCredsAttrValue(BaseModel): + """AnonCreds attribute value.""" class Meta: - """Anoncreds attribute value.""" + """AnonCreds attribute value.""" - schema_class = "AnoncredsAttrValueSchema" + schema_class = "AnonCredsAttrValueSchema" def __init__( self, raw: Optional[str] = None, encoded: Optional[str] = None, **kwargs @@ -34,13 +34,13 @@ def __init__( self.encoded = encoded -class AnoncredsAttrValueSchema(BaseModelSchema): - """Anoncreds attribute value schema.""" +class AnonCredsAttrValueSchema(BaseModelSchema): + """AnonCreds attribute value schema.""" class Meta: - """Anoncreds attribute value schema metadata.""" + """AnonCreds attribute value schema metadata.""" - model_class = AnoncredsAttrValue + model_class = AnonCredsAttrValue unknown = EXCLUDE raw = fields.Str(required=True, metadata={"description": "Attribute raw value"}) @@ -54,14 +54,14 @@ class Meta: ) -class DictWithAnoncredsAttrValueSchema(fields.Dict): +class DictWithAnonCredsAttrValueSchema(fields.Dict): """Dict with anoncreds attribute value schema.""" def __init__(self, **kwargs): - """Initialize the custom schema for a dictionary with AnoncredsAttrValue.""" + """Initialize the custom schema for a dictionary with AnonCredsAttrValue.""" super().__init__( keys=fields.Str(metadata={"description": "Attribute name"}), - values=fields.Nested(AnoncredsAttrValueSchema()), + values=fields.Nested(AnonCredsAttrValueSchema()), **kwargs, ) @@ -71,7 +71,7 @@ def _deserialize(self, value, attr, data, **kwargs): raise ValidationError("Value must be a dict.") errors = {} - anoncreds_attr_value_schema = AnoncredsAttrValueSchema() + anoncreds_attr_value_schema = AnonCredsAttrValueSchema() for k, v in value.items(): if isinstance(v, dict): @@ -85,20 +85,20 @@ def _deserialize(self, value, attr, data, **kwargs): return value -class AnoncredsCredential(BaseModel): - """Anoncreds credential.""" +class AnonCredsCredential(BaseModel): + """AnonCreds credential.""" class Meta: - """Anoncreds credential metadata.""" + """AnonCreds credential metadata.""" - schema_class = "AnoncredsCredentialSchema" + schema_class = "AnonCredsCredentialSchema" def __init__( self, schema_id: Optional[str] = None, cred_def_id: Optional[str] = None, rev_reg_id: Optional[str] = None, - values: Mapping[str, AnoncredsAttrValue] = None, + values: Mapping[str, AnonCredsAttrValue] = None, signature: Optional[Mapping] = None, signature_correctness_proof: Optional[Mapping] = None, rev_reg: Optional[Mapping] = None, @@ -115,13 +115,13 @@ def __init__( self.witness = witness -class AnoncredsCredentialSchema(BaseModelSchema): - """Anoncreds credential schema.""" +class AnonCredsCredentialSchema(BaseModelSchema): + """AnonCreds credential schema.""" class Meta: - """Anoncreds credential schemametadata.""" + """AnonCreds credential schemametadata.""" - model_class = AnoncredsCredential + model_class = AnonCredsCredential unknown = EXCLUDE schema_id = fields.Str( @@ -148,7 +148,7 @@ class Meta: "example": ANONCREDS_REV_REG_ID_EXAMPLE, }, ) - values = DictWithAnoncredsAttrValueSchema( + values = DictWithAnonCredsAttrValueSchema( required=True, metadata={"description": "Credential attributes"}, ) diff --git a/acapy_agent/anoncreds/models/credential_definition.py b/acapy_agent/anoncreds/models/credential_definition.py index 4e543eaf57..f2961b8b9a 100644 --- a/acapy_agent/anoncreds/models/credential_definition.py +++ b/acapy_agent/anoncreds/models/credential_definition.py @@ -1,4 +1,4 @@ -"""Anoncreds cred def OpenAPI validators.""" +"""AnonCreds cred def OpenAPI validators.""" from typing import Optional @@ -28,7 +28,7 @@ class CredDefValuePrimary(BaseModel): class Meta: """PrimarySchema metadata.""" - schema_class = "CredDefValuePrimarySchemaAnoncreds" + schema_class = "CredDefValuePrimarySchemaAnonCreds" def __init__(self, n: str, s: str, r: dict, rctxt: str, z: str, **kwargs): """Initialize an instance. @@ -53,7 +53,7 @@ def __init__(self, n: str, s: str, r: dict, rctxt: str, z: str, **kwargs): self.z = z -class CredDefValuePrimarySchemaAnoncreds(BaseModelSchema): +class CredDefValuePrimarySchemaAnonCreds(BaseModelSchema): """Cred def value primary schema.""" class Meta: @@ -75,7 +75,7 @@ class CredDefValueRevocation(BaseModel): class Meta: """CredDefValueRevocation metadata.""" - schema_class = "CredDefValueRevocationSchemaAnoncreds" + schema_class = "CredDefValueRevocationSchemaAnonCreds" def __init__( self, @@ -122,7 +122,7 @@ def __init__( self.y = y -class CredDefValueRevocationSchemaAnoncreds(BaseModelSchema): +class CredDefValueRevocationSchemaAnonCreds(BaseModelSchema): """Cred def value revocation schema.""" class Meta: @@ -160,7 +160,7 @@ class CredDefValue(BaseModel): class Meta: """CredDefValue metadata.""" - schema_class = "CredDefValueSchemaAnoncreds" + schema_class = "CredDefValueSchemaAnonCreds" def __init__( self, @@ -180,7 +180,7 @@ def __init__( self.revocation = revocation -class CredDefValueSchemaAnoncreds(BaseModelSchema): +class CredDefValueSchemaAnonCreds(BaseModelSchema): """Cred def value schema.""" class Meta: @@ -190,11 +190,11 @@ class Meta: unknown = EXCLUDE primary = fields.Nested( - CredDefValuePrimarySchemaAnoncreds(), + CredDefValuePrimarySchemaAnonCreds(), metadata={"description": "Primary value for credential definition"}, ) revocation = fields.Nested( - CredDefValueRevocationSchemaAnoncreds(), + CredDefValueRevocationSchemaAnonCreds(), metadata={"description": "Revocation value for credential definition"}, required=False, ) @@ -277,7 +277,7 @@ class Meta: "example": "default", } ) - value = fields.Nested(CredDefValueSchemaAnoncreds()) + value = fields.Nested(CredDefValueSchemaAnonCreds()) class CredDefState(BaseModel): diff --git a/acapy_agent/anoncreds/models/credential_offer.py b/acapy_agent/anoncreds/models/credential_offer.py index c77419eba3..27219a751d 100644 --- a/acapy_agent/anoncreds/models/credential_offer.py +++ b/acapy_agent/anoncreds/models/credential_offer.py @@ -1,4 +1,4 @@ -"""Anoncreds Credential Offer format for v2.0 of the issue-credential protocol.""" +"""AnonCreds Credential Offer format for v2.0 of the issue-credential protocol.""" from typing import Optional, Sequence @@ -15,13 +15,13 @@ ) -class AnoncredsKeyCorrectnessProof(BaseModel): - """Anoncreds key correctness proof.""" +class AnonCredsKeyCorrectnessProof(BaseModel): + """AnonCreds key correctness proof.""" class Meta: - """AnoncredsKeyCorrectnessProof metadata.""" + """AnonCredsKeyCorrectnessProof metadata.""" - schema_class = "AnoncredsKeyCorrectnessProofSchema" + schema_class = "AnonCredsKeyCorrectnessProofSchema" def __init__( self, @@ -38,13 +38,13 @@ def __init__( self.xr_cap = xr_cap -class AnoncredsCorrectnessProofSchema(BaseModelSchema): - """Anoncreds key correctness proof schema.""" +class AnonCredsCorrectnessProofSchema(BaseModelSchema): + """AnonCreds key correctness proof schema.""" class Meta: - """Anoncreds key correctness proof schema metadata.""" + """AnonCreds key correctness proof schema metadata.""" - model_class = AnoncredsKeyCorrectnessProof + model_class = AnonCredsKeyCorrectnessProof unknown = EXCLUDE c = fields.Str( @@ -82,13 +82,13 @@ class Meta: ) -class AnoncredsCredentialOffer(BaseModel): - """Anoncreds Credential Offer.""" +class AnonCredsCredentialOffer(BaseModel): + """AnonCreds Credential Offer.""" class Meta: - """AnoncredsCredentialOffer metadata.""" + """AnonCredsCredentialOffer metadata.""" - schema_class = "AnoncredsCredentialOfferSchema" + schema_class = "AnonCredsCredentialOfferSchema" def __init__( self, @@ -106,13 +106,13 @@ def __init__( self.key_correctness_proof = key_correctness_proof -class AnoncredsCredentialOfferSchema(BaseModelSchema): - """Anoncreds Credential Offer Schema.""" +class AnonCredsCredentialOfferSchema(BaseModelSchema): + """AnonCreds Credential Offer Schema.""" class Meta: - """AnoncredsCredentialOffer schema metadata.""" + """AnonCredsCredentialOffer schema metadata.""" - model_class = AnoncredsCredentialOffer + model_class = AnonCredsCredentialOffer unknown = EXCLUDE schema_id = fields.Str( @@ -143,7 +143,7 @@ class Meta: ) key_correctness_proof = fields.Nested( - AnoncredsCorrectnessProofSchema(), + AnonCredsCorrectnessProofSchema(), required=True, metadata={"description": "Key correctness proof"}, ) diff --git a/acapy_agent/anoncreds/models/credential_proposal.py b/acapy_agent/anoncreds/models/credential_proposal.py index ba7365b292..cac1ec027a 100644 --- a/acapy_agent/anoncreds/models/credential_proposal.py +++ b/acapy_agent/anoncreds/models/credential_proposal.py @@ -1,4 +1,4 @@ -"""Anoncreds credential definition proposal.""" +"""AnonCreds credential definition proposal.""" import re @@ -19,7 +19,7 @@ ) -class AnoncredsCredentialDefinitionProposal(OpenAPISchema): +class AnonCredsCredentialDefinitionProposal(OpenAPISchema): """Query string parameters for credential definition searches.""" cred_def_id = fields.Str( @@ -69,7 +69,7 @@ class AnoncredsCredentialDefinitionProposal(OpenAPISchema): CRED_DEF_TAGS = list( - vars(AnoncredsCredentialDefinitionProposal).get("_declared_fields", []) + vars(AnonCredsCredentialDefinitionProposal).get("_declared_fields", []) ) CRED_DEF_EVENT_PREFIX = "acapy::CRED_DEF::" diff --git a/acapy_agent/anoncreds/models/credential_request.py b/acapy_agent/anoncreds/models/credential_request.py index 2d5147b4a6..34577e2e4a 100644 --- a/acapy_agent/anoncreds/models/credential_request.py +++ b/acapy_agent/anoncreds/models/credential_request.py @@ -14,13 +14,13 @@ ) -class AnoncredsCredRequest(BaseModel): - """Anoncreds credential request.""" +class AnonCredsCredRequest(BaseModel): + """AnonCreds credential request.""" class Meta: - """Anoncreds credential request metadata.""" + """AnonCreds credential request metadata.""" - schema_class = "AnoncredsCredRequestSchema" + schema_class = "AnonCredsCredRequestSchema" def __init__( self, @@ -43,13 +43,13 @@ def __init__( self.nonce = nonce -class AnoncredsCredRequestSchema(BaseModelSchema): - """Anoncreds credential request schema.""" +class AnonCredsCredRequestSchema(BaseModelSchema): + """AnonCreds credential request schema.""" class Meta: - """Anoncreds credential request schema metadata.""" + """AnonCreds credential request schema metadata.""" - model_class = AnoncredsCredRequest + model_class = AnonCredsCredRequest unknown = EXCLUDE entropy = fields.Str( diff --git a/acapy_agent/anoncreds/models/non_rev_interval.py b/acapy_agent/anoncreds/models/non_rev_interval.py index a224891189..181de931c7 100644 --- a/acapy_agent/anoncreds/models/non_rev_interval.py +++ b/acapy_agent/anoncreds/models/non_rev_interval.py @@ -1,4 +1,4 @@ -"""Anoncreds non-revocation interval.""" +"""AnonCreds non-revocation interval.""" from time import time from typing import Optional @@ -9,13 +9,13 @@ from ...messaging.valid import INT_EPOCH_EXAMPLE, INT_EPOCH_VALIDATE -class AnoncredsNonRevocationInterval(BaseModel): - """Anoncreds non-revocation interval.""" +class AnonCredsNonRevocationInterval(BaseModel): + """AnonCreds non-revocation interval.""" class Meta: """NonRevocationInterval metadata.""" - schema_class = "AnoncredsNonRevocationIntervalSchema" + schema_class = "AnonCredsNonRevocationIntervalSchema" def __init__(self, fro: Optional[int] = None, to: Optional[int] = None, **kwargs): """Initialize non-revocation interval. @@ -48,13 +48,13 @@ def timestamp(self) -> bool: return self.to or self.fro or int(time()) -class AnoncredsNonRevocationIntervalSchema(BaseModelSchema): +class AnonCredsNonRevocationIntervalSchema(BaseModelSchema): """Schema to allow serialization/deserialization of non-revocation intervals.""" class Meta: - """AnoncredsNonRevocationIntervalSchema metadata.""" + """AnonCredsNonRevocationIntervalSchema metadata.""" - model_class = AnoncredsNonRevocationInterval + model_class = AnonCredsNonRevocationInterval unknown = EXCLUDE fro = fields.Int( diff --git a/acapy_agent/anoncreds/models/presentation_request.py b/acapy_agent/anoncreds/models/presentation_request.py index 12855e1ee6..aa9df77996 100644 --- a/acapy_agent/anoncreds/models/presentation_request.py +++ b/acapy_agent/anoncreds/models/presentation_request.py @@ -26,7 +26,7 @@ ) -class AnoncredsPresentationReqPredSpecSchema(OpenAPISchema): +class AnonCredsPresentationReqPredSpecSchema(OpenAPISchema): """Schema for predicate specification in anoncreds proof request.""" name = fields.Str( @@ -90,14 +90,14 @@ class AnoncredsPresentationReqPredSpecSchema(OpenAPISchema): }, ), }, - name="AnoncredsPresentationReqPredSpecNonRevokedSchema", + name="AnonCredsPresentationReqPredSpecNonRevokedSchema", ), allow_none=True, required=False, ) -class AnoncredsPresentationReqAttrSpecSchema(OpenAPISchema): +class AnonCredsPresentationReqAttrSpecSchema(OpenAPISchema): """Schema for attribute specification in anoncreds proof request.""" name = fields.Str( @@ -156,7 +156,7 @@ class AnoncredsPresentationReqAttrSpecSchema(OpenAPISchema): }, ), }, - name="AnoncredsPresentationReqAttrSpecNonRevokedSchema", + name="AnonCredsPresentationReqAttrSpecNonRevokedSchema", ), allow_none=True, required=False, @@ -188,13 +188,13 @@ def validate_fields(self, data, **kwargs): ) -class AnoncredsPresentationRequest(BaseModel): +class AnonCredsPresentationRequest(BaseModel): """anoncreds proof request.""" class Meta: - """Anoncreds proof request metadata.""" + """AnonCreds proof request metadata.""" - schema_class = "AnoncredsPresentationRequestSchema" + schema_class = "AnonCredsPresentationRequestSchema" def __init__( self, @@ -229,13 +229,13 @@ def __init__( self.non_revoked = non_revoked -class AnoncredsPresentationRequestSchema(BaseModelSchema): +class AnonCredsPresentationRequestSchema(BaseModelSchema): """Schema for anoncreds proof request.""" class Meta: - """Anoncreds proof request schema metadata.""" + """AnonCreds proof request schema metadata.""" - model_class = AnoncredsPresentationRequest + model_class = AnonCredsPresentationRequest unknown = EXCLUDE nonce = fields.Str( @@ -262,7 +262,7 @@ class Meta: keys=fields.Str( metadata={"decription": "Attribute referent", "example": "0_legalname_uuid"} ), - values=fields.Nested(AnoncredsPresentationReqAttrSpecSchema()), + values=fields.Nested(AnonCredsPresentationReqAttrSpecSchema()), metadata={"description": "Requested attribute specifications of proof request"}, ) requested_predicates = fields.Dict( @@ -270,7 +270,7 @@ class Meta: keys=fields.Str( metadata={"description": "Predicate referent", "example": "0_age_GE_uuid"} ), - values=fields.Nested(AnoncredsPresentationReqPredSpecSchema()), + values=fields.Nested(AnonCredsPresentationReqPredSpecSchema()), metadata={"description": "Requested predicate specifications of proof request"}, ) non_revoked = fields.Nested( @@ -299,7 +299,7 @@ class Meta: }, ), }, - name="AnoncredsPresentationRequestNonRevokedSchema", + name="AnonCredsPresentationRequestNonRevokedSchema", ), allow_none=True, required=False, diff --git a/acapy_agent/anoncreds/models/proof.py b/acapy_agent/anoncreds/models/proof.py index 817b947cc5..622ebd6bbb 100644 --- a/acapy_agent/anoncreds/models/proof.py +++ b/acapy_agent/anoncreds/models/proof.py @@ -22,18 +22,18 @@ from ...utils.tracing import AdminAPIMessageTracingSchema from .predicate import Predicate from .requested_credentials import ( - AnoncredsRequestedCredsRequestedAttrSchema, - AnoncredsRequestedCredsRequestedPredSchema, + AnonCredsRequestedCredsRequestedAttrSchema, + AnonCredsRequestedCredsRequestedPredSchema, ) -class AnoncredsEQProof(BaseModel): +class AnonCredsEQProof(BaseModel): """Equality proof for anoncreds primary proof.""" class Meta: """Equality proof metadata.""" - schema_class = "AnoncredsEQProofMeta" + schema_class = "AnonCredsEQProofMeta" def __init__( self, @@ -55,13 +55,13 @@ def __init__( self.m2 = m2 -class AnoncredsEQProofSchema(BaseModelSchema): - """Anoncreds equality proof schema.""" +class AnonCredsEQProofSchema(BaseModelSchema): + """AnonCreds equality proof schema.""" class Meta: - """Anoncreds equality proof metadata.""" + """AnonCreds equality proof metadata.""" - model_class = AnoncredsEQProof + model_class = AnonCredsEQProof unknown = EXCLUDE revealed_attrs = fields.Dict( @@ -90,13 +90,13 @@ class Meta: ) -class AnoncredsGEProofPred(BaseModel): - """Anoncreds GE proof predicate.""" +class AnonCredsGEProofPred(BaseModel): + """AnonCreds GE proof predicate.""" class Meta: - """Anoncreds GE proof predicate metadata.""" + """AnonCreds GE proof predicate metadata.""" - schema_class = "AnoncredsGEProofPredSchema" + schema_class = "AnonCredsGEProofPredSchema" def __init__( self, @@ -112,13 +112,13 @@ def __init__( self.value = value -class AnoncredsGEProofPredSchema(BaseModelSchema): - """Anoncreds GE proof predicate schema.""" +class AnonCredsGEProofPredSchema(BaseModelSchema): + """AnonCreds GE proof predicate schema.""" class Meta: - """Anoncreds GE proof predicate metadata.""" + """AnonCreds GE proof predicate metadata.""" - model_class = AnoncredsGEProofPred + model_class = AnonCredsGEProofPred unknown = EXCLUDE attr_name = fields.Str( @@ -133,13 +133,13 @@ class Meta: ) -class AnoncredsGEProof(BaseModel): +class AnonCredsGEProof(BaseModel): """Greater-than-or-equal-to proof for anoncreds primary proof.""" class Meta: """GE proof metadata.""" - schema_class = "AnoncredsGEProofMeta" + schema_class = "AnonCredsGEProofMeta" def __init__( self, @@ -148,7 +148,7 @@ def __init__( mj: Optional[str] = None, alpha: Optional[str] = None, t: Mapping[str, str] = None, - predicate: Optional[AnoncredsGEProofPred] = None, + predicate: Optional[AnonCredsGEProofPred] = None, **kwargs, ): """Initialize GE proof object.""" @@ -161,13 +161,13 @@ def __init__( self.predicate = predicate -class AnoncredsGEProofSchema(BaseModelSchema): - """Anoncreds GE proof schema.""" +class AnonCredsGEProofSchema(BaseModelSchema): + """AnonCreds GE proof schema.""" class Meta: - """Anoncreds GE proof schema metadata.""" + """AnonCreds GE proof schema metadata.""" - model_class = AnoncredsGEProof + model_class = AnonCredsGEProof unknown = EXCLUDE u = fields.Dict( @@ -194,21 +194,21 @@ class Meta: validate=NUM_STR_WHOLE_VALIDATE, metadata={"example": NUM_STR_WHOLE_EXAMPLE} ), ) - predicate = fields.Nested(AnoncredsGEProofPredSchema) + predicate = fields.Nested(AnonCredsGEProofPredSchema) -class AnoncredsPrimaryProof(BaseModel): - """Anoncreds primary proof.""" +class AnonCredsPrimaryProof(BaseModel): + """AnonCreds primary proof.""" class Meta: - """Anoncreds primary proof metadata.""" + """AnonCreds primary proof metadata.""" - schema_class = "AnoncredsPrimaryProofSchema" + schema_class = "AnonCredsPrimaryProofSchema" def __init__( self, - eq_proof: Optional[AnoncredsEQProof] = None, - ge_proofs: Sequence[AnoncredsGEProof] = None, + eq_proof: Optional[AnonCredsEQProof] = None, + ge_proofs: Sequence[AnonCredsGEProof] = None, **kwargs, ): """Initialize anoncreds primary proof.""" @@ -217,35 +217,35 @@ def __init__( self.ge_proofs = ge_proofs -class AnoncredsPrimaryProofSchema(BaseModelSchema): - """Anoncreds primary proof schema.""" +class AnonCredsPrimaryProofSchema(BaseModelSchema): + """AnonCreds primary proof schema.""" class Meta: - """Anoncreds primary proof schema metadata.""" + """AnonCreds primary proof schema metadata.""" - model_class = AnoncredsPrimaryProof + model_class = AnonCredsPrimaryProof unknown = EXCLUDE eq_proof = fields.Nested( - AnoncredsEQProofSchema, + AnonCredsEQProofSchema, allow_none=True, - metadata={"description": "Anoncreds equality proof"}, + metadata={"description": "AnonCreds equality proof"}, ) ge_proofs = fields.Nested( - AnoncredsGEProofSchema, + AnonCredsGEProofSchema, many=True, allow_none=True, - metadata={"description": "Anoncreds GE proofs"}, + metadata={"description": "AnonCreds GE proofs"}, ) -class AnoncredsNonRevocProof(BaseModel): - """Anoncreds non-revocation proof.""" +class AnonCredsNonRevocProof(BaseModel): + """AnonCreds non-revocation proof.""" class Meta: - """Anoncreds non-revocation proof metadata.""" + """AnonCreds non-revocation proof metadata.""" - schema_class = "AnoncredsNonRevocProofSchema" + schema_class = "AnonCredsNonRevocProofSchema" def __init__( self, @@ -259,31 +259,31 @@ def __init__( self.c_list = c_list -class AnoncredsNonRevocProofSchema(BaseModelSchema): - """Anoncreds non-revocation proof schema.""" +class AnonCredsNonRevocProofSchema(BaseModelSchema): + """AnonCreds non-revocation proof schema.""" class Meta: - """Anoncreds non-revocation proof schema metadata.""" + """AnonCreds non-revocation proof schema metadata.""" - model_class = AnoncredsNonRevocProof + model_class = AnonCredsNonRevocProof unknown = EXCLUDE x_list = fields.Dict(keys=fields.Str(), values=fields.Str()) c_list = fields.Dict(keys=fields.Str(), values=fields.Str()) -class AnoncredsProofProofProofsProof(BaseModel): - """Anoncreds proof.proof.proofs constituent proof.""" +class AnonCredsProofProofProofsProof(BaseModel): + """AnonCreds proof.proof.proofs constituent proof.""" class Meta: - """Anoncreds proof.proof.proofs constituent proof schema.""" + """AnonCreds proof.proof.proofs constituent proof schema.""" - schema_class = "AnoncredsProofProofProofsProofSchema" + schema_class = "AnonCredsProofProofProofsProofSchema" def __init__( self, - primary_proof: Optional[AnoncredsPrimaryProof] = None, - non_revoc_proof: Optional[AnoncredsNonRevocProof] = None, + primary_proof: Optional[AnonCredsPrimaryProof] = None, + non_revoc_proof: Optional[AnonCredsNonRevocProof] = None, **kwargs, ): """Initialize proof.proof.proofs constituent proof.""" @@ -292,32 +292,32 @@ def __init__( self.non_revoc_proof = non_revoc_proof -class AnoncredsProofProofProofsProofSchema(BaseModelSchema): - """Anoncreds proof.proof.proofs constituent proof schema.""" +class AnonCredsProofProofProofsProofSchema(BaseModelSchema): + """AnonCreds proof.proof.proofs constituent proof schema.""" class Meta: - """Anoncreds proof.proof.proofs constituent proof schema metadata.""" + """AnonCreds proof.proof.proofs constituent proof schema metadata.""" - model_class = AnoncredsProofProofProofsProof + model_class = AnonCredsProofProofProofsProof unknown = EXCLUDE primary_proof = fields.Nested( - AnoncredsPrimaryProofSchema, metadata={"description": "Anoncreds primary proof"} + AnonCredsPrimaryProofSchema, metadata={"description": "AnonCreds primary proof"} ) non_revoc_proof = fields.Nested( - AnoncredsNonRevocProofSchema, + AnonCredsNonRevocProofSchema, allow_none=True, - metadata={"description": "Anoncreds non-revocation proof"}, + metadata={"description": "AnonCreds non-revocation proof"}, ) -class AnoncredsProofProofAggregatedProof(BaseModel): - """Anoncreds proof.proof aggregated proof.""" +class AnonCredsProofProofAggregatedProof(BaseModel): + """AnonCreds proof.proof aggregated proof.""" class Meta: - """Anoncreds proof.proof aggregated proof metadata.""" + """AnonCreds proof.proof aggregated proof metadata.""" - schema_class = "AnoncredsProofProofAggregatedProofSchema" + schema_class = "AnonCredsProofProofAggregatedProofSchema" def __init__( self, @@ -331,13 +331,13 @@ def __init__( self.c_list = c_list -class AnoncredsProofProofAggregatedProofSchema(BaseModelSchema): - """Anoncreds proof.proof aggregated proof schema.""" +class AnonCredsProofProofAggregatedProofSchema(BaseModelSchema): + """AnonCreds proof.proof aggregated proof schema.""" class Meta: - """Anoncreds proof.proof aggregated proof schema metadata.""" + """AnonCreds proof.proof aggregated proof schema metadata.""" - model_class = AnoncredsProofProofAggregatedProof + model_class = AnonCredsProofProofAggregatedProof unknown = EXCLUDE c_hash = fields.Str(metadata={"description": "c_hash value"}) @@ -347,18 +347,18 @@ class Meta: ) -class AnoncredsProofProof(BaseModel): - """Anoncreds proof.proof content.""" +class AnonCredsProofProof(BaseModel): + """AnonCreds proof.proof content.""" class Meta: - """Anoncreds proof.proof content metadata.""" + """AnonCreds proof.proof content metadata.""" - schema_class = "AnoncredsProofProofSchema" + schema_class = "AnonCredsProofProofSchema" def __init__( self, - proofs: Sequence[AnoncredsProofProofProofsProof] = None, - aggregated_proof: Optional[AnoncredsProofProofAggregatedProof] = None, + proofs: Sequence[AnonCredsProofProofProofsProof] = None, + aggregated_proof: Optional[AnonCredsProofProofAggregatedProof] = None, **kwargs, ): """Initialize anoncreds proof.proof content.""" @@ -367,23 +367,23 @@ def __init__( self.aggregated_proof = aggregated_proof -class AnoncredsProofProofSchema(BaseModelSchema): - """Anoncreds proof.proof content schema.""" +class AnonCredsProofProofSchema(BaseModelSchema): + """AnonCreds proof.proof content schema.""" class Meta: - """Anoncreds proof.proof content schema metadata.""" + """AnonCreds proof.proof content schema metadata.""" - model_class = AnoncredsProofProof + model_class = AnonCredsProofProof unknown = EXCLUDE proofs = fields.Nested( - AnoncredsProofProofProofsProofSchema, + AnonCredsProofProofProofsProofSchema, many=True, - metadata={"description": "Anoncreds proof proofs"}, + metadata={"description": "AnonCreds proof proofs"}, ) aggregated_proof = fields.Nested( - AnoncredsProofProofAggregatedProofSchema, - metadata={"description": "Anoncreds proof aggregated proof"}, + AnonCredsProofProofAggregatedProofSchema, + metadata={"description": "AnonCreds proof aggregated proof"}, ) @@ -423,13 +423,13 @@ class Meta: ) -class AnoncredsProofRequestedProofRevealedAttr(RawEncoded): - """Anoncreds proof requested proof revealed attr.""" +class AnonCredsProofRequestedProofRevealedAttr(RawEncoded): + """AnonCreds proof requested proof revealed attr.""" class Meta: - """Anoncreds proof requested proof revealed attr metadata.""" + """AnonCreds proof requested proof revealed attr metadata.""" - schema_class = "AnoncredsProofRequestedProofRevealedAttrSchema" + schema_class = "AnonCredsProofRequestedProofRevealedAttrSchema" def __init__( self, @@ -441,13 +441,13 @@ def __init__( self.sub_proof_index = sub_proof_index -class AnoncredsProofRequestedProofRevealedAttrSchema(RawEncodedSchema): - """Anoncreds proof requested proof revealed attr schema.""" +class AnonCredsProofRequestedProofRevealedAttrSchema(RawEncodedSchema): + """AnonCreds proof requested proof revealed attr schema.""" class Meta: - """Anoncreds proof requested proof revealed attr schema metadata.""" + """AnonCreds proof requested proof revealed attr schema metadata.""" - model_class = AnoncredsProofRequestedProofRevealedAttr + model_class = AnonCredsProofRequestedProofRevealedAttr unknown = EXCLUDE sub_proof_index = fields.Int( @@ -455,13 +455,13 @@ class Meta: ) -class AnoncredsProofRequestedProofRevealedAttrGroup(BaseModel): - """Anoncreds proof requested proof revealed attr group.""" +class AnonCredsProofRequestedProofRevealedAttrGroup(BaseModel): + """AnonCreds proof requested proof revealed attr group.""" class Meta: - """Anoncreds proof requested proof revealed attr group metadata.""" + """AnonCreds proof requested proof revealed attr group metadata.""" - schema_class = "AnoncredsProofRequestedProofRevealedAttrGroupSchema" + schema_class = "AnonCredsProofRequestedProofRevealedAttrGroupSchema" def __init__( self, @@ -475,13 +475,13 @@ def __init__( self.values = values -class AnoncredsProofRequestedProofRevealedAttrGroupSchema(BaseModelSchema): - """Anoncreds proof requested proof revealed attr group schema.""" +class AnonCredsProofRequestedProofRevealedAttrGroupSchema(BaseModelSchema): + """AnonCreds proof requested proof revealed attr group schema.""" class Meta: - """Anoncreds proof requested proof revealed attr group schema metadata.""" + """AnonCreds proof requested proof revealed attr group schema metadata.""" - model_class = AnoncredsProofRequestedProofRevealedAttrGroup + model_class = AnonCredsProofRequestedProofRevealedAttrGroup unknown = EXCLUDE sub_proof_index = fields.Int( @@ -491,18 +491,18 @@ class Meta: keys=fields.Str(), values=fields.Nested(RawEncodedSchema), metadata={ - "description": "Anoncreds proof requested proof revealed attr groups group value" # noqa: E501 + "description": "AnonCreds proof requested proof revealed attr groups group value" # noqa: E501 }, ) -class AnoncredsProofRequestedProofPredicate(BaseModel): - """Anoncreds proof requested proof predicate.""" +class AnonCredsProofRequestedProofPredicate(BaseModel): + """AnonCreds proof requested proof predicate.""" class Meta: - """Anoncreds proof requested proof requested proof predicate metadata.""" + """AnonCreds proof requested proof requested proof predicate metadata.""" - schema_class = "AnoncredsProofRequestedProofPredicateSchema" + schema_class = "AnonCredsProofRequestedProofPredicateSchema" def __init__( self, @@ -514,13 +514,13 @@ def __init__( self.sub_proof_index = sub_proof_index -class AnoncredsProofRequestedProofPredicateSchema(BaseModelSchema): - """Anoncreds proof requested prrof predicate schema.""" +class AnonCredsProofRequestedProofPredicateSchema(BaseModelSchema): + """AnonCreds proof requested prrof predicate schema.""" class Meta: - """Anoncreds proof requested proof requested proof predicate schema metadata.""" + """AnonCreds proof requested proof requested proof predicate schema metadata.""" - model_class = AnoncredsProofRequestedProofPredicate + model_class = AnonCredsProofRequestedProofPredicate unknown = EXCLUDE sub_proof_index = fields.Int( @@ -528,24 +528,24 @@ class Meta: ) -class AnoncredsProofRequestedProof(BaseModel): - """Anoncreds proof.requested_proof content.""" +class AnonCredsProofRequestedProof(BaseModel): + """AnonCreds proof.requested_proof content.""" class Meta: - """Anoncreds proof.requested_proof content metadata.""" + """AnonCreds proof.requested_proof content metadata.""" - schema_class = "AnoncredsProofRequestedProofSchema" + schema_class = "AnonCredsProofRequestedProofSchema" def __init__( self, - revealed_attrs: Mapping[str, AnoncredsProofRequestedProofRevealedAttr] = None, + revealed_attrs: Mapping[str, AnonCredsProofRequestedProofRevealedAttr] = None, revealed_attr_groups: Mapping[ str, - AnoncredsProofRequestedProofRevealedAttrGroup, + AnonCredsProofRequestedProofRevealedAttrGroup, ] = None, self_attested_attrs: Optional[Mapping] = None, unrevealed_attrs: Optional[Mapping] = None, - predicates: Mapping[str, AnoncredsProofRequestedProofPredicate] = None, + predicates: Mapping[str, AnonCredsProofRequestedProofPredicate] = None, **kwargs, ): """Initialize anoncreds proof requested proof.""" @@ -557,24 +557,24 @@ def __init__( self.predicates = predicates -class AnoncredsProofRequestedProofSchema(BaseModelSchema): - """Anoncreds proof requested proof schema.""" +class AnonCredsProofRequestedProofSchema(BaseModelSchema): + """AnonCreds proof requested proof schema.""" class Meta: - """Anoncreds proof requested proof schema metadata.""" + """AnonCreds proof requested proof schema metadata.""" - model_class = AnoncredsProofRequestedProof + model_class = AnonCredsProofRequestedProof unknown = EXCLUDE revealed_attrs = fields.Dict( keys=fields.Str(), - values=fields.Nested(AnoncredsProofRequestedProofRevealedAttrSchema), + values=fields.Nested(AnonCredsProofRequestedProofRevealedAttrSchema), allow_none=True, metadata={"description": "Proof requested proof revealed attributes"}, ) revealed_attr_groups = fields.Dict( keys=fields.Str(), - values=fields.Nested(AnoncredsProofRequestedProofRevealedAttrGroupSchema), + values=fields.Nested(AnonCredsProofRequestedProofRevealedAttrGroupSchema), allow_none=True, metadata={"description": "Proof requested proof revealed attribute groups"}, ) @@ -584,18 +584,18 @@ class Meta: unrevealed_attrs = fields.Dict(metadata={"description": "Unrevealed attributes"}) predicates = fields.Dict( keys=fields.Str(), - values=fields.Nested(AnoncredsProofRequestedProofPredicateSchema), + values=fields.Nested(AnonCredsProofRequestedProofPredicateSchema), metadata={"description": "Proof requested proof predicates."}, ) -class AnoncredsProofIdentifier(BaseModel): - """Anoncreds proof identifier.""" +class AnonCredsProofIdentifier(BaseModel): + """AnonCreds proof identifier.""" class Meta: - """Anoncreds proof identifier metadata.""" + """AnonCreds proof identifier metadata.""" - schema_class = "AnoncredsProofIdentifierSchema" + schema_class = "AnonCredsProofIdentifierSchema" def __init__( self, @@ -613,13 +613,13 @@ def __init__( self.timestamp = timestamp -class AnoncredsProofIdentifierSchema(BaseModelSchema): - """Anoncreds proof identifier schema.""" +class AnonCredsProofIdentifierSchema(BaseModelSchema): + """AnonCreds proof identifier schema.""" class Meta: - """Anoncreds proof identifier schema metadata.""" + """AnonCreds proof identifier schema metadata.""" - model_class = AnoncredsProofIdentifier + model_class = AnonCredsProofIdentifier unknown = EXCLUDE schema_id = fields.Str( @@ -655,19 +655,19 @@ class Meta: ) -class AnoncredsProof(BaseModel): - """Anoncreds proof.""" +class AnonCredsProof(BaseModel): + """AnonCreds proof.""" class Meta: - """Anoncreds proof metadata.""" + """AnonCreds proof metadata.""" - schema_class = "AnoncredsProofSchema" + schema_class = "AnonCredsProofSchema" def __init__( self, - proof: Optional[AnoncredsProofProof] = None, - requested_proof: Optional[AnoncredsProofRequestedProof] = None, - identifiers: Sequence[AnoncredsProofIdentifier] = None, + proof: Optional[AnonCredsProofProof] = None, + requested_proof: Optional[AnonCredsProofRequestedProof] = None, + identifiers: Sequence[AnonCredsProofIdentifier] = None, **kwargs, ): """Initialize anoncreds proof.""" @@ -677,31 +677,31 @@ def __init__( self.identifiers = identifiers -class AnoncredsProofSchema(BaseModelSchema): - """Anoncreds proof schema.""" +class AnonCredsProofSchema(BaseModelSchema): + """AnonCreds proof schema.""" class Meta: - """Anoncreds proof schema metadata.""" + """AnonCreds proof schema metadata.""" - model_class = AnoncredsProof + model_class = AnonCredsProof unknown = EXCLUDE proof = fields.Nested( - AnoncredsProofProofSchema, - metadata={"description": "Anoncreds proof.proof content"}, + AnonCredsProofProofSchema, + metadata={"description": "AnonCreds proof.proof content"}, ) requested_proof = fields.Nested( - AnoncredsProofRequestedProofSchema, - metadata={"description": "Anoncreds proof.requested_proof content"}, + AnonCredsProofRequestedProofSchema, + metadata={"description": "AnonCreds proof.requested_proof content"}, ) identifiers = fields.Nested( - AnoncredsProofIdentifierSchema, + AnonCredsProofIdentifierSchema, many=True, - metadata={"description": "Anoncreds proof.identifiers content"}, + metadata={"description": "AnonCreds proof.identifiers content"}, ) -class AnoncredsPresSpecSchema(AdminAPIMessageTracingSchema): +class AnonCredsPresSpecSchema(AdminAPIMessageTracingSchema): """Request schema for anoncreds proof specification to send as presentation.""" self_attested_attributes = fields.Dict( @@ -721,7 +721,7 @@ class AnoncredsPresSpecSchema(AdminAPIMessageTracingSchema): requested_attributes = fields.Dict( required=True, keys=fields.Str(metadata={"example": "attr_referent"}), - values=fields.Nested(AnoncredsRequestedCredsRequestedAttrSchema), + values=fields.Nested(AnonCredsRequestedCredsRequestedAttrSchema), metadata={ "description": ( "Nested object mapping proof request attribute referents to" @@ -732,7 +732,7 @@ class AnoncredsPresSpecSchema(AdminAPIMessageTracingSchema): requested_predicates = fields.Dict( required=True, keys=fields.Str(metadata={"example": "pred_referent"}), - values=fields.Nested(AnoncredsRequestedCredsRequestedPredSchema), + values=fields.Nested(AnonCredsRequestedCredsRequestedPredSchema), metadata={ "description": ( "Nested object mapping proof request predicate referents to" diff --git a/acapy_agent/anoncreds/models/requested_credentials.py b/acapy_agent/anoncreds/models/requested_credentials.py index ac0fcf3d33..49b2e097aa 100644 --- a/acapy_agent/anoncreds/models/requested_credentials.py +++ b/acapy_agent/anoncreds/models/requested_credentials.py @@ -6,7 +6,7 @@ from ...messaging.valid import INT_EPOCH_EXAMPLE, INT_EPOCH_VALIDATE -class AnoncredsRequestedCredsRequestedAttrSchema(OpenAPISchema): +class AnonCredsRequestedCredsRequestedAttrSchema(OpenAPISchema): """Schema for requested attributes within anoncreds requested creds structure.""" cred_id = fields.Str( @@ -24,7 +24,7 @@ class AnoncredsRequestedCredsRequestedAttrSchema(OpenAPISchema): ) -class AnoncredsRequestedCredsRequestedPredSchema(OpenAPISchema): +class AnonCredsRequestedCredsRequestedPredSchema(OpenAPISchema): """Schema for requested predicates within anoncreds requested creds structure.""" cred_id = fields.Str( diff --git a/acapy_agent/anoncreds/models/revocation.py b/acapy_agent/anoncreds/models/revocation.py index 94c75a525a..50bbd0e388 100644 --- a/acapy_agent/anoncreds/models/revocation.py +++ b/acapy_agent/anoncreds/models/revocation.py @@ -1,4 +1,4 @@ -"""Anoncreds cred def OpenAPI validators.""" +"""AnonCreds cred def OpenAPI validators.""" from typing import Any, Dict, List, Optional diff --git a/acapy_agent/anoncreds/models/schema.py b/acapy_agent/anoncreds/models/schema.py index 1a3e3152d2..c513b3afd3 100644 --- a/acapy_agent/anoncreds/models/schema.py +++ b/acapy_agent/anoncreds/models/schema.py @@ -1,4 +1,4 @@ -"""Anoncreds Schema OpenAPI validators.""" +"""AnonCreds Schema OpenAPI validators.""" from typing import Any, Dict, List, Optional @@ -7,10 +7,7 @@ from marshmallow.validate import OneOf from ...messaging.models.base import BaseModel, BaseModelSchema -from ...messaging.valid import ( - ANONCREDS_DID_EXAMPLE, - ANONCREDS_SCHEMA_ID_EXAMPLE, -) +from ...messaging.valid import ANONCREDS_DID_EXAMPLE, ANONCREDS_SCHEMA_ID_EXAMPLE class AnonCredsSchema(BaseModel): diff --git a/acapy_agent/anoncreds/models/schema_info.py b/acapy_agent/anoncreds/models/schema_info.py index e5cda7100d..81bd7ee0e6 100644 --- a/acapy_agent/anoncreds/models/schema_info.py +++ b/acapy_agent/anoncreds/models/schema_info.py @@ -3,7 +3,7 @@ from typing import Optional -class AnoncredsSchemaInfo: +class AnonCredsSchemaInfo: """Represents the schema information for anonymous credentials. Attributes: diff --git a/acapy_agent/anoncreds/registry.py b/acapy_agent/anoncreds/registry.py index 92b70ac516..ae4e9b9afb 100644 --- a/acapy_agent/anoncreds/registry.py +++ b/acapy_agent/anoncreds/registry.py @@ -21,7 +21,7 @@ RevRegDefResult, ) from .models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult -from .models.schema_info import AnoncredsSchemaInfo +from .models.schema_info import AnonCredsSchemaInfo LOGGER = logging.getLogger(__name__) @@ -102,7 +102,7 @@ async def get_credential_definition( async def get_schema_info_by_id( self, profile: Profile, schema_id: str - ) -> AnoncredsSchemaInfo: + ) -> AnonCredsSchemaInfo: """Get a schema info from the registry.""" resolver = await self._resolver_for_identifier(schema_id) return await resolver.get_schema_info_by_id(profile, schema_id) diff --git a/acapy_agent/anoncreds/revocation.py b/acapy_agent/anoncreds/revocation.py index 251923f103..8acf23b671 100644 --- a/acapy_agent/anoncreds/revocation.py +++ b/acapy_agent/anoncreds/revocation.py @@ -26,7 +26,7 @@ from requests import RequestException, Session from uuid_utils import uuid4 -from ..askar.profile_anon import AskarAnoncredsProfile, AskarAnoncredsProfileSession +from ..askar.profile_anon import AskarAnonCredsProfile, AskarAnonCredsProfileSession from ..core.error import BaseError from ..core.event_bus import Event, EventBus from ..core.profile import Profile, ProfileSession @@ -92,9 +92,9 @@ def __init__(self, profile: Profile): self._profile = profile @property - def profile(self) -> AskarAnoncredsProfile: + def profile(self) -> AskarAnonCredsProfile: """Accessor for the profile instance.""" - if not isinstance(self._profile, AskarAnoncredsProfile): + if not isinstance(self._profile, AskarAnonCredsProfile): raise ValueError(ANONCREDS_PROFILE_REQUIRED_MSG) return self._profile @@ -106,7 +106,7 @@ async def notify(self, event: Event): async def _finish_registration( self, - txn: AskarAnoncredsProfileSession, + txn: AskarAnonCredsProfileSession, category: str, job_id: str, registered_id: str, @@ -477,7 +477,7 @@ async def store_revocation_registry_list(self, result: RevListResult): identifier, value_json={ "rev_list": rev_list.serialize(), - # Anoncreds uses the 0 index internally + # AnonCreds uses the 0 index internally # and can't be used for a credential "next_index": 1, "pending": None, @@ -1497,7 +1497,7 @@ async def clear_pending_revocations( crid_mask: Optional[Sequence[int]] = None, ): """Clear pending revocations.""" - if not isinstance(txn, AskarAnoncredsProfileSession): + if not isinstance(txn, AskarAnonCredsProfileSession): raise ValueError("Askar wallet required") entry = await txn.handle.fetch( diff --git a/acapy_agent/anoncreds/routes.py b/acapy_agent/anoncreds/routes.py index 8d5a37e034..28ee72041b 100644 --- a/acapy_agent/anoncreds/routes.py +++ b/acapy_agent/anoncreds/routes.py @@ -1,4 +1,4 @@ -"""Anoncreds admin routes.""" +"""AnonCreds admin routes.""" import logging from asyncio import shield @@ -62,7 +62,7 @@ ) -class AnoncredsRevocationModuleResponseSchema(OpenAPISchema): +class AnonCredsRevocationModuleResponseSchema(OpenAPISchema): """Response schema for Revocation Module.""" @@ -584,7 +584,7 @@ class RevRegDefOptionsSchema(OpenAPISchema): ) -class RevRegCreateRequestSchemaAnoncreds(OpenAPISchema): +class RevRegCreateRequestSchemaAnonCreds(OpenAPISchema): """Wrapper for revocation registry creation request.""" revocation_registry_definition = fields.Nested(InnerRevRegDefSchema()) @@ -595,7 +595,7 @@ class RevRegCreateRequestSchemaAnoncreds(OpenAPISchema): tags=["anoncreds - revocation"], summary="Create and publish a registration revocation on the connected datastore", ) -@request_schema(RevRegCreateRequestSchemaAnoncreds()) +@request_schema(RevRegCreateRequestSchemaAnonCreds()) @response_schema(RevRegDefResultSchema(), 200, description="") @tenant_authentication async def rev_reg_def_post(request: web.BaseRequest): @@ -717,7 +717,7 @@ async def rev_list_post(request: web.BaseRequest): summary="Upload local tails file to server", ) @match_info_schema(AnonCredsRevRegIdMatchInfoSchema()) -@response_schema(AnoncredsRevocationModuleResponseSchema(), description="") +@response_schema(AnonCredsRevocationModuleResponseSchema(), description="") @tenant_authentication async def upload_tails_file(request: web.BaseRequest): """Request handler to upload local tails file for revocation registry. @@ -753,7 +753,7 @@ async def upload_tails_file(request: web.BaseRequest): summary="Update the active registry", ) @match_info_schema(AnonCredsRevRegIdMatchInfoSchema()) -@response_schema(AnoncredsRevocationModuleResponseSchema(), description="") +@response_schema(AnonCredsRevocationModuleResponseSchema(), description="") @tenant_authentication async def set_active_registry(request: web.BaseRequest): """Request handler to set the active registry. @@ -820,15 +820,15 @@ def post_process_routes(app: web.Application): app._state["swagger_dict"]["tags"] = [] app._state["swagger_dict"]["tags"].append( { - "name": "anoncreds - schemas", - "description": "Anoncreds schema management", + "name": "AnonCreds - Schemas", + "description": "AnonCreds schema management", "externalDocs": {"description": "Specification", "url": SPEC_URI}, } ) app._state["swagger_dict"]["tags"].append( { - "name": "anoncreds - credential definitions", - "description": "Anoncreds credential definition management", + "name": "AnonCreds - Credential Definitions", + "description": "AnonCreds credential definition management", "externalDocs": {"description": "Specification", "url": SPEC_URI}, } ) diff --git a/acapy_agent/anoncreds/tests/test_holder.py b/acapy_agent/anoncreds/tests/test_holder.py index c442fd76bb..532d2b6655 100644 --- a/acapy_agent/anoncreds/tests/test_holder.py +++ b/acapy_agent/anoncreds/tests/test_holder.py @@ -35,10 +35,7 @@ MOCK_W3CPRES, SCHEMAS, ) -from ...askar.profile_anon import ( - AskarAnoncredsProfile, - AskarAnoncredsProfileSession, -) +from ...askar.profile_anon import AskarAnonCredsProfile, AskarAnonCredsProfileSession from ...tests import mock from ...utils.testing import create_test_profile from ...vc.ld_proofs.document_loader import DocumentLoader @@ -148,15 +145,15 @@ async def asyncSetUp(self): async def test_init(self): assert isinstance(self.holder, AnonCredsHolder) - assert isinstance(self.holder.profile, AskarAnoncredsProfile) + assert isinstance(self.holder.profile, AskarAnonCredsProfile) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_get_master_secret(self, mock_session_handle): mock_session_handle.fetch = mock.CoroutineMock(return_value=MockMasterSecret()) secret = await self.holder.get_master_secret() assert secret is not None - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_get_master_secret_errors(self, mock_session_handle): # Not found mock_session_handle.fetch = mock.CoroutineMock( @@ -165,7 +162,7 @@ async def test_get_master_secret_errors(self, mock_session_handle): with self.assertRaises(AnonCredsHolderError): await self.holder.get_master_secret() - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_get_master_secret_does_not_return_master_secret( self, mock_session_handle ): @@ -418,7 +415,7 @@ async def test_get_credentials_for_presentation_request_by_referent(self): ) @mock.patch.object(Credential, "load", return_value=MockCredential()) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_get_credential(self, mock_handle, _): mock_handle.fetch = mock.CoroutineMock(side_effect=[MockCredEntry(), None]) result = await self.holder.get_credential("cred-id") @@ -428,7 +425,7 @@ async def test_get_credential(self, mock_handle, _): await self.holder.get_credential("cred-id") @mock.patch.object(Credential, "load", return_value=MockCredential()) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_credential_revoked(self, mock_handle, _): mock_registry = mock.MagicMock(AnonCredsRegistry, autospec=True) mock_registry.get_revocation_list = mock.CoroutineMock( @@ -460,7 +457,7 @@ async def test_credential_revoked(self, mock_handle, _): is False ) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_delete_credential(self, mock_handle): mock_handle.remove = mock.CoroutineMock( side_effect=[ @@ -479,7 +476,7 @@ async def test_delete_credential(self, mock_handle): with self.assertRaises(AnonCredsHolderError): await self.holder.delete_credential("cred-id") - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_get_mime_type(self, mock_handle): mock_handle.fetch = mock.CoroutineMock( side_effect=[ @@ -495,7 +492,7 @@ async def test_get_mime_type(self, mock_handle): await self.holder.get_mime_type("cred-id", "mime-type") @mock.patch.object(Credential, "load", return_value=MockCredential()) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(AnonCredsHolder, "get_master_secret", return_value="master-secret") @mock.patch.object( anoncreds.Presentation, "create", return_value=Presentation.load(MOCK_PRES) @@ -544,7 +541,7 @@ async def test_create_presentation( ) @mock.patch.object(Credential, "load", return_value=MockCredential()) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(AnonCredsHolder, "get_master_secret", return_value="master-secret") @mock.patch.object( anoncreds.Presentation, "create", return_value=Presentation.load(MOCK_PRES) @@ -637,7 +634,7 @@ async def test_create_presentation_with_revocation( assert mock_master_secret.called assert mock_handle.fetch.called - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(AnonCredsHolder, "get_master_secret", return_value="master-secret") @mock.patch.object( anoncreds.Presentation, @@ -662,7 +659,7 @@ async def test_create_presentation_create_error( rev_states={}, ) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(AnonCredsHolder, "get_master_secret", return_value="master-secret") @mock.patch.object( anoncreds.W3cPresentation, @@ -685,7 +682,7 @@ async def test_create_presentation_w3c( assert mock_master_secret.called mock_handle.fetch.assert_called - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(AnonCredsHolder, "get_master_secret", return_value="master-secret") @mock.patch.object( anoncreds.W3cPresentation, diff --git a/acapy_agent/anoncreds/tests/test_issuer.py b/acapy_agent/anoncreds/tests/test_issuer.py index 361e7f794b..0b9de21ee6 100644 --- a/acapy_agent/anoncreds/tests/test_issuer.py +++ b/acapy_agent/anoncreds/tests/test_issuer.py @@ -3,13 +3,16 @@ from unittest import IsolatedAsyncioTestCase import pytest -from anoncreds import Credential, CredentialDefinition, CredentialOffer, W3cCredential +from anoncreds import ( + AnoncredsError, + Credential, + CredentialDefinition, + CredentialOffer, + W3cCredential, +) from aries_askar import AskarError, AskarErrorCode -from ...anoncreds.base import ( - AnonCredsObjectAlreadyExists, - AnonCredsSchemaAlreadyExists, -) +from ...anoncreds.base import AnonCredsObjectAlreadyExists, AnonCredsSchemaAlreadyExists from ...anoncreds.models.credential_definition import ( CredDef, CredDefResult, @@ -25,10 +28,7 @@ SchemaResult, SchemaState, ) -from ...askar.profile_anon import ( - AskarAnoncredsProfile, - AskarAnoncredsProfileSession, -) +from ...askar.profile_anon import AskarAnonCredsProfile, AskarAnonCredsProfileSession from ...core.event_bus import Event, MockEventBus from ...tests import mock from ...utils.testing import create_test_profile @@ -127,7 +127,7 @@ async def asyncSetUp(self) -> None: async def test_init(self): assert isinstance(self.issuer, test_module.AnonCredsIssuer) - assert isinstance(self.issuer.profile, AskarAnoncredsProfile) + assert isinstance(self.issuer.profile, AskarAnonCredsProfile) async def test_init_wrong_profile_type(self): self.issuer._profile = await create_test_profile( @@ -140,7 +140,7 @@ async def test_notify(self): self.profile.inject = mock.Mock(return_value=MockEventBus()) await self.issuer.notify(Event(topic="test-topic")) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(AnonCredsSchema, "deserialize", return_value="test") async def test_create_and_register_schema_finds_schema_raises_x( self, _, mock_session_handle @@ -161,7 +161,7 @@ async def test_create_and_register_schema_finds_schema_raises_x( attr_names=["attr1", "attr2"], ) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_create_and_register_schema(self, mock_session_handle): mock_session_handle.fetch_all = mock.CoroutineMock(return_value=[]) mock_session_handle.insert = mock.CoroutineMock(return_value=None) @@ -181,7 +181,7 @@ async def test_create_and_register_schema(self, mock_session_handle): mock_session_handle.fetch_all.assert_called_once() mock_session_handle.insert.assert_called_once() - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_create_and_register_schema_missing_schema_id_or_job_id( self, mock_session_handle ): @@ -259,7 +259,7 @@ async def test_create_and_register_schema_missing_schema_id_or_job_id( attr_names=["attr1", "attr2"], ) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_create_and_register_schema_fail_insert(self, mock_session_handle): mock_session_handle.fetch_all = mock.CoroutineMock(return_value=[]) mock_session_handle.insert = mock.CoroutineMock( @@ -283,7 +283,7 @@ async def test_create_and_register_schema_fail_insert(self, mock_session_handle) mock_session_handle.fetch_all.assert_called_once() mock_session_handle.insert.assert_called_once() - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_create_and_register_schema_already_exists_but_not_in_wallet( self, mock_session_handle ): @@ -313,7 +313,7 @@ async def test_create_and_register_schema_already_exists_but_not_in_wallet( attr_names=["attr1", "attr2"], ) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_create_and_register_schema_without_job_id_or_schema_id_raises_x( self, mock_session_handle ): @@ -350,7 +350,7 @@ async def test_create_and_register_schema_without_job_id_or_schema_id_raises_x( attr_names=["attr1", "attr2"], ) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(test_module.AnonCredsIssuer, "store_schema") async def test_create_and_register_schema_with_endorsed_transaction_response_does_not_store_schema( self, mock_store_schema, mock_session_handle @@ -394,7 +394,7 @@ async def test_finish_schema(self): ) await self.issuer.finish_schema(job_id="job-id", schema_id="schema-id") - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_get_created_schemas(self, mock_session_handle): mock_session_handle.fetch_all = mock.CoroutineMock( return_value=[MockSchemaEntry("name-test")] @@ -413,7 +413,7 @@ async def test_get_created_schemas(self, mock_session_handle): mock_session_handle.fetch_all.assert_called_once() assert result == ["schema1", "schema2"] - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_credential_definition_in_wallet(self, mock_session_handle): mock_session_handle.fetch = mock.CoroutineMock( side_effect=[ @@ -731,7 +731,7 @@ async def test_create_and_register_credential_definition_errors(self, mock_notif ) ) # Creating fails with bad issuer_id - with self.assertRaises(test_module.AnoncredsError): + with self.assertRaises(AnoncredsError): await self.issuer.create_and_register_credential_definition( issuer_id="issuer-id", schema_id="CsQY9MGeD3CQP4EyuVFo5m:2:MYCO Biomarker:0.0.3", @@ -747,7 +747,7 @@ async def test_create_and_register_credential_definition_errors(self, mock_notif options={}, ) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_get_created_cred_defs(self, mock_session_handle): mock_session_handle.fetch_all = mock.CoroutineMock( return_value=[MockCredDefEntry()] @@ -769,7 +769,7 @@ async def test_get_created_cred_defs(self, mock_session_handle): mock_session_handle.fetch_all.assert_called_once() assert result == ["cred_def1", "cred_def2"] - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_match_created_cred_defs(self, mock_session_handle): mock_session_handle.fetch_all = mock.CoroutineMock( return_value=[ @@ -782,7 +782,7 @@ async def test_match_created_cred_defs(self, mock_session_handle): result = await self.issuer.match_created_credential_definitions() assert result == "name4" - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_create_credential_offer_cred_def_not_found(self, mock_session_handle): """ None, Valid @@ -859,7 +859,7 @@ async def test_cred_def_supports_revocation(self): result = await self.issuer.cred_def_supports_revocation("cred-def-id") assert result is True - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(CredentialDefinition, "load", return_value=MockCredDefEntry()) async def test_create_credential_offer_create_fail( self, mock_load, mock_session_handle @@ -872,7 +872,7 @@ async def test_create_credential_offer_create_fail( assert mock_session_handle.fetch.called assert mock_load.called - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(CredentialDefinition, "load", return_value=MockCredDefEntry()) @mock.patch.object(CredentialOffer, "create", return_value=MockCredOffer()) async def test_create_credential_offer_create( @@ -887,7 +887,7 @@ async def test_create_credential_offer_create( assert mock_create.called assert result is not None - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(Credential, "create", return_value=MockCredential()) async def test_create_credential(self, mock_create, mock_session_handle): self.profile.inject = mock.Mock( @@ -906,7 +906,7 @@ async def test_create_credential(self, mock_create, mock_session_handle): assert mock_session_handle.fetch.called assert mock_create.called - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(W3cCredential, "create", return_value=MockCredential()) async def test_create_credential_vcdi(self, mock_create, mock_session_handle): self.profile.inject = mock.Mock( diff --git a/acapy_agent/anoncreds/tests/test_revocation.py b/acapy_agent/anoncreds/tests/test_revocation.py index db3013fc35..33f91a3518 100644 --- a/acapy_agent/anoncreds/tests/test_revocation.py +++ b/acapy_agent/anoncreds/tests/test_revocation.py @@ -31,7 +31,7 @@ from ...anoncreds.registry import AnonCredsRegistry from ...anoncreds.tests.mock_objects import MOCK_REV_REG_DEF from ...anoncreds.tests.test_issuer import MockCredDefEntry -from ...askar.profile_anon import AskarAnoncredsProfileSession +from ...askar.profile_anon import AskarAnonCredsProfileSession from ...core.event_bus import Event, EventBus, MockEventBus from ...tails.anoncreds_tails_server import AnonCredsTailsServer from ...tests import mock @@ -134,7 +134,7 @@ async def test_notify(self): async def test_create_and_register_revocation_registry_definition_fails_to_get_cred_def( self, ): - # Anoncreds error + # AnonCreds error with self.assertRaises(test_module.AnonCredsRevocationError): await self.revocation.create_and_register_revocation_registry_definition( issuer_id="test-issuer-id", @@ -153,7 +153,7 @@ async def test_create_and_register_revocation_registry_definition_fails_to_get_c max_cred_num=100, ) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object( test_module.AnonCredsRevocation, "generate_public_tails_uri", @@ -345,7 +345,7 @@ async def test_create_and_register_revocation_registry_definition( max_cred_num=100, ) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(RevRegDef, "from_json", return_value="rev-reg-def") @mock.patch.object(test_module.AnonCredsRevocation, "notify") async def test_finish_revocation_registry_definition( @@ -368,7 +368,7 @@ async def test_finish_revocation_registry_definition( rev_reg_def_id="rev-reg-def-id", ) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_get_created_revocation_registry_definitions(self, mock_handle): mock_handle.fetch_all = mock.CoroutineMock( return_value=[ @@ -379,7 +379,7 @@ async def test_get_created_revocation_registry_definitions(self, mock_handle): result = await self.revocation.get_created_revocation_registry_definitions() assert result == ["revocation_reg_def_0", "revocation_reg_def_1"] - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_get_created_revocation_registry_definition_state(self, mock_handle): mock_handle.fetch = mock.CoroutineMock( side_effect=[MockEntry(tags={"state": RevRegDefState.STATE_FINISHED}), None] @@ -393,7 +393,7 @@ async def test_get_created_revocation_registry_definition_state(self, mock_handl ) assert result is None - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_get_created_revocation_registry_definition(self, mock_handle): mock_handle.fetch = mock.CoroutineMock( side_effect=[ @@ -425,7 +425,7 @@ async def test_get_created_revocation_registry_definition(self, mock_handle): ) assert result is None - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_set_active_registry(self, mock_handle): mock_handle.fetch = mock.CoroutineMock(return_value=None) mock_handle.replace = mock.CoroutineMock(return_value=None) @@ -464,7 +464,7 @@ async def test_set_active_registry(self, mock_handle): assert mock_handle.fetch_all.call_count == 1 assert mock_handle.replace.call_count == 3 - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_create_and_register_revocation_list_errors(self, mock_handle): class MockEntry: value_json = { @@ -492,7 +492,7 @@ class MockEntry: rev_reg_def_id="test-rev-reg-def-id", ) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(RevRegDef, "deserialize") @mock.patch.object(CredDef, "deserialize") @mock.patch.object(RevocationRegistryDefinitionPrivate, "load") @@ -566,7 +566,7 @@ async def test_create_and_register_revocation_list( AnonCredsRegistry )._instance.register_revocation_list.called - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(test_module.AnonCredsRevocation, "_finish_registration") async def test_finish_revocation_list(self, mock_finish, mock_handle): self.profile.context.injector.bind_instance(EventBus, MockEventBus()) @@ -585,7 +585,7 @@ async def test_finish_revocation_list(self, mock_finish, mock_handle): ) assert mock_finish.call_count == 1 - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_update_revocation_list_get_rev_reg_errors(self, mock_handle): mock_handle.fetch = mock.CoroutineMock( side_effect=[ @@ -610,7 +610,7 @@ async def test_update_revocation_list_get_rev_reg_errors(self, mock_handle): revoked=[1, 1, 0, 0], ) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_update_revocation_list(self, mock_handle): mock_handle.fetch = mock.CoroutineMock( side_effect=[ @@ -730,7 +730,7 @@ async def test_update_revocation_list(self, mock_handle): revoked=[1, 1, 0, 0], ) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_get_created_revocation_list(self, mock_handle): mock_handle.fetch = mock.CoroutineMock( side_effect=[ @@ -751,7 +751,7 @@ async def test_get_created_revocation_list(self, mock_handle): with self.assertRaises(test_module.AnonCredsRevocationError): await self.revocation.get_created_revocation_list("rev-reg-def-id") - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_get_revocation_lists_with_pending_revocations(self, mock_handle): mock_handle.fetch_all = mock.CoroutineMock( side_effect=[ @@ -879,7 +879,7 @@ async def test_upload_tails_file(self): ): await self.revocation.upload_tails_file(rev_reg_def) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object( test_module.AnonCredsRevocation, "set_active_registry", return_value=None ) @@ -912,7 +912,7 @@ async def test_handle_full_registry( with self.assertRaises(test_module.AnonCredsRevocationError): await self.revocation.handle_full_registry("test-rev-reg-def-id") - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_decommission_registry(self, mock_handle): mock_handle.fetch_all = mock.CoroutineMock( return_value=[ @@ -977,7 +977,7 @@ async def test_decommission_registry(self, mock_handle): == 2 ) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_get_or_create_active_registry(self, mock_handle): mock_handle.fetch_all = mock.CoroutineMock( side_effect=[ @@ -1003,7 +1003,7 @@ async def test_get_or_create_active_registry(self, mock_handle): with self.assertRaises(test_module.AnonCredsRevocationError): await self.revocation.get_or_create_active_registry("test-rev-reg-def-id") - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(Credential, "create", return_value=mock.MagicMock()) async def test_create_credential_private_no_rev_reg_or_tails( self, mock_create, mock_handle @@ -1067,7 +1067,7 @@ async def test_create_credential_private_no_rev_reg_or_tails( RevocationRegistryDefinition, "load", return_value=rev_reg_def.value ) @mock.patch("acapy_agent.anoncreds.revocation.CredentialRevocationConfig") - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(Credential, "create", return_value=mock.MagicMock()) async def test_create_credential_private_with_rev_reg_and_tails( self, mock_create, mock_handle, *_ @@ -1200,7 +1200,7 @@ async def test_create_credential(self, mock_supports_revocation): assert isinstance(result, tuple) assert mock_supports_revocation.call_count == 1 - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(RevList, "to_native") @mock.patch.object(RevList, "from_native", return_value=None) @mock.patch.object(RevRegDef, "to_native") @@ -1298,7 +1298,7 @@ async def test_revoke_pending_credentials( assert mock_deserialize_cred_def.called assert isinstance(result, test_module.RevokeResult) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(RevList, "to_native") @mock.patch.object(RevList, "from_native", return_value=None) @mock.patch.object(RevRegDef, "to_native") @@ -1335,7 +1335,7 @@ async def test_revoke_pending_credentials_cred_def_error( ) assert "Error retrieving cred def" in str(cm.exception) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(RevList, "to_native") @mock.patch.object(RevList, "from_native", return_value=None) @mock.patch.object(RevRegDef, "to_native") @@ -1375,7 +1375,7 @@ async def test_revoke_pending_credentials_anoncreds_error( ) assert "Error loading revocation registry definition" in str(cm.exception) - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") @mock.patch.object(RevList, "to_native") @mock.patch.object(RevList, "from_native", return_value=None) @mock.patch.object(RevRegDef, "to_native") @@ -1412,7 +1412,7 @@ async def test_revoke_pending_credentials_no_valid_credentials( assert result.revoked == [] # No credentials were revoked assert result.failed == [] # No failures - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_mark_pending_revocations(self, mock_handle): mock_handle.fetch = mock.CoroutineMock( side_effect=[ @@ -1434,7 +1434,7 @@ async def test_mark_pending_revocations(self, mock_handle): await self.revocation.mark_pending_revocations("test-rev-reg-id", int("200")) assert mock_handle.replace.call_count == 1 - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_get_pending_revocations(self, mock_handle): mock_handle.fetch = mock.CoroutineMock( side_effect=[ @@ -1454,7 +1454,7 @@ async def test_get_pending_revocations(self, mock_handle): assert result == [1, 2] @mock.patch("acapy_agent.anoncreds.revocation.isinstance") - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_clear_pending_revocations(self, mock_handle, mock_is_instance): mock_handle.fetch = mock.CoroutineMock( side_effect=[ @@ -1547,7 +1547,7 @@ async def test_create_credential_w3c(self, mock_supports_revocation): assert isinstance(result, tuple) assert mock_supports_revocation.call_count == 1 - @mock.patch.object(AskarAnoncredsProfileSession, "handle") + @mock.patch.object(AskarAnonCredsProfileSession, "handle") async def test_create_credential_w3c_keyerror(self, mock_handle): mock_handle.fetch = mock.CoroutineMock(side_effect=[MockEntry(), MockEntry()]) with pytest.raises(test_module.AnonCredsRevocationError) as excinfo: diff --git a/acapy_agent/anoncreds/tests/test_routes.py b/acapy_agent/anoncreds/tests/test_routes.py index c59af1a662..7de707629c 100644 --- a/acapy_agent/anoncreds/tests/test_routes.py +++ b/acapy_agent/anoncreds/tests/test_routes.py @@ -7,11 +7,7 @@ from ...admin.request_context import AdminRequestContext from ...anoncreds.base import AnonCredsObjectNotFound from ...anoncreds.issuer import AnonCredsIssuer -from ...anoncreds.models.schema import ( - AnonCredsSchema, - SchemaResult, - SchemaState, -) +from ...anoncreds.models.schema import AnonCredsSchema, SchemaResult, SchemaState from ...anoncreds.revocation import AnonCredsRevocation from ...anoncreds.revocation_setup import DefaultRevocationSetup from ...core.event_bus import MockEventBus @@ -45,7 +41,7 @@ def serialize(self): @pytest.mark.anoncreds -class TestAnoncredsRoutes(IsolatedAsyncioTestCase): +class TestAnonCredsRoutes(IsolatedAsyncioTestCase): async def asyncSetUp(self) -> None: self.session_inject = {} self.profile = await create_test_profile( diff --git a/acapy_agent/anoncreds/tests/test_verifier.py b/acapy_agent/anoncreds/tests/test_verifier.py index 0ff11fcb95..f3bd516d2f 100644 --- a/acapy_agent/anoncreds/tests/test_verifier.py +++ b/acapy_agent/anoncreds/tests/test_verifier.py @@ -17,10 +17,7 @@ RevRegDef, RevRegDefValue, ) -from ...anoncreds.models.schema import ( - AnonCredsSchema, - GetSchemaResult, -) +from ...anoncreds.models.schema import AnonCredsSchema, GetSchemaResult from ...tests import mock from ...utils.testing import create_test_profile from .. import verifier as test_module diff --git a/acapy_agent/anoncreds/verifier.py b/acapy_agent/anoncreds/verifier.py index daeaeef7ce..a2f454c43b 100644 --- a/acapy_agent/anoncreds/verifier.py +++ b/acapy_agent/anoncreds/verifier.py @@ -1,4 +1,4 @@ -"""Anoncreds verifier implementation.""" +"""AnonCreds verifier implementation.""" import asyncio import logging diff --git a/acapy_agent/askar/profile_anon.py b/acapy_agent/askar/profile_anon.py index 90c6e7a09d..b684dc952f 100644 --- a/acapy_agent/askar/profile_anon.py +++ b/acapy_agent/askar/profile_anon.py @@ -30,7 +30,7 @@ LOGGER = logging.getLogger(__name__) -class AskarAnoncredsProfile(Profile): +class AskarAnonCredsProfile(Profile): """Provide access to Aries-Askar profile interaction methods.""" BACKEND_NAME = "askar-anoncreds" @@ -161,19 +161,19 @@ def bind_providers(self): def session( self, context: Optional[InjectionContext] = None - ) -> "AskarAnoncredsProfileSession": + ) -> "AskarAnonCredsProfileSession": """Start a new interactive session with no transaction support requested.""" - return AskarAnoncredsProfileSession(self, False, context=context) + return AskarAnonCredsProfileSession(self, False, context=context) def transaction( self, context: Optional[InjectionContext] = None - ) -> "AskarAnoncredsProfileSession": + ) -> "AskarAnonCredsProfileSession": """Start a new interactive session with commit and rollback support. If the current backend does not support transactions, then commit and rollback operations of the session will not have any effect. """ - return AskarAnoncredsProfileSession(self, True, context=context) + return AskarAnonCredsProfileSession(self, True, context=context) async def close(self): """Close the profile instance.""" @@ -182,18 +182,18 @@ async def close(self): self.opened = None -class AskarAnoncredsProfileSession(ProfileSession): +class AskarAnonCredsProfileSession(ProfileSession): """An active connection to the profile management backend.""" def __init__( self, - profile: AskarAnoncredsProfile, + profile: AskarAnonCredsProfile, is_txn: bool, *, context: Optional[InjectionContext] = None, settings: Mapping[str, Any] = None, ): - """Create a new AskarAnoncredsProfileSession instance.""" + """Create a new AskarAnonCredsProfileSession instance.""" super().__init__(profile=profile, context=context, settings=settings) if is_txn: self._opener = self.profile.store.transaction(profile.profile_id) @@ -282,7 +282,7 @@ async def provision( opened = await store_config.open_store( provision=True, in_memory=config.get("test") ) - return AskarAnoncredsProfile(opened, context) + return AskarAnonCredsProfile(opened, context) async def open( self, context: InjectionContext, config: Mapping[str, Any] = None @@ -292,7 +292,7 @@ async def open( opened = await store_config.open_store( provision=False, in_memory=config.get("test") ) - return AskarAnoncredsProfile(opened, context) + return AskarAnonCredsProfile(opened, context) @classmethod async def generate_store_key(self, seed: Optional[str] = None) -> str: diff --git a/acapy_agent/commands/tests/test_provision.py b/acapy_agent/commands/tests/test_provision.py index ed50bb9eb8..49c1a4682c 100644 --- a/acapy_agent/commands/tests/test_provision.py +++ b/acapy_agent/commands/tests/test_provision.py @@ -4,9 +4,7 @@ from ...config.base import ConfigError from ...config.error import ArgsParseError -from ...protocols.coordinate_mediation.mediation_invite_store import ( - MediationInviteRecord, -) +from ...protocols.coordinate_mediation.mediation_invite_store import MediationInviteRecord from ...utils.testing import create_test_profile from .. import provision as test_module diff --git a/acapy_agent/config/logging/__init__.py b/acapy_agent/config/logging/__init__.py index a1e96b5c3b..1e862498da 100644 --- a/acapy_agent/config/logging/__init__.py +++ b/acapy_agent/config/logging/__init__.py @@ -3,7 +3,7 @@ DEFAULT_MULTITENANT_LOGGING_CONFIG_PATH_INI, LOG_FORMAT_FILE_ALIAS_PATTERN, ) -from .configurator import LoggingConfigurator, load_resource, fileConfig +from .configurator import LoggingConfigurator, fileConfig, load_resource from .filters import ContextFilter, context_wallet_id from .timed_rotating_file_multi_process_handler import ( TimedRotatingFileMultiProcessHandler, diff --git a/acapy_agent/connections/base_manager.py b/acapy_agent/connections/base_manager.py index cd06b8f89f..3e2aa713a5 100644 --- a/acapy_agent/connections/base_manager.py +++ b/acapy_agent/connections/base_manager.py @@ -5,8 +5,8 @@ import json import logging -from typing import Dict, List, Optional, Sequence, Text, Tuple, Union import warnings +from typing import Dict, List, Optional, Sequence, Text, Tuple, Union import pydid from base58 import b58decode @@ -29,11 +29,9 @@ from ..core.profile import Profile from ..did.did_key import DIDKey from ..multitenant.base import BaseMultitenantManager -from ..protocols.didexchange.v1_0.message_types import ARIES_PROTOCOL as CONN_PROTO -from ..protocols.coordinate_mediation.v1_0.models.mediation_record import ( - MediationRecord, -) +from ..protocols.coordinate_mediation.v1_0.models.mediation_record import MediationRecord from ..protocols.coordinate_mediation.v1_0.route_manager import RouteManager +from ..protocols.didexchange.v1_0.message_types import ARIES_PROTOCOL as CONN_PROTO from ..protocols.discovery.v2_0.manager import V20DiscoveryMgr from ..protocols.out_of_band.v1_0.messages.invitation import InvitationMessage from ..resolver.base import ResolverError diff --git a/acapy_agent/connections/tests/test_base_manager.py b/acapy_agent/connections/tests/test_base_manager.py index 5d4ff0cd6b..958f567bb3 100644 --- a/acapy_agent/connections/tests/test_base_manager.py +++ b/acapy_agent/connections/tests/test_base_manager.py @@ -5,6 +5,7 @@ from unittest.mock import call import base58 +import pytest from pydid import DID, DIDDocument, DIDDocumentBuilder from pydid.doc.builder import ServiceBuilder from pydid.verification_method import ( @@ -13,7 +14,6 @@ Ed25519VerificationKey2020, JsonWebKey2020, ) -import pytest from ...cache.base import BaseCache from ...cache.in_memory import InMemoryCache @@ -45,7 +45,7 @@ from ...utils.testing import create_test_profile from ...wallet.askar import AskarWallet from ...wallet.base import BaseWallet, DIDInfo -from ...wallet.did_method import DIDMethods, SOV +from ...wallet.did_method import SOV, DIDMethods from ...wallet.error import WalletNotFoundError from ...wallet.key_type import ED25519, KeyTypes from ...wallet.util import b58_to_bytes, bytes_to_b64 diff --git a/acapy_agent/connections/tests/test_routes.py b/acapy_agent/connections/tests/test_routes.py index 5613924f61..f75ae2d968 100644 --- a/acapy_agent/connections/tests/test_routes.py +++ b/acapy_agent/connections/tests/test_routes.py @@ -1,7 +1,6 @@ from unittest import IsolatedAsyncioTestCase from unittest.mock import ANY -from .. import routes as test_module from ...admin.request_context import AdminRequestContext from ...cache.base import BaseCache from ...cache.in_memory import InMemoryCache @@ -9,6 +8,7 @@ from ...storage.error import StorageNotFoundError from ...tests import mock from ...utils.testing import create_test_profile +from .. import routes as test_module class TestConnectionRoutes(IsolatedAsyncioTestCase): diff --git a/acapy_agent/did/did_key.py b/acapy_agent/did/did_key.py index 2213e715a1..b62ce1cc14 100644 --- a/acapy_agent/did/did_key.py +++ b/acapy_agent/did/did_key.py @@ -1,6 +1,7 @@ """DID Key class and resolver methods.""" from typing import List, Optional + from ..vc.ld_proofs.constants import DID_V1_CONTEXT_URL, SECURITY_CONTEXT_MULTIKEY_URL from ..wallet.crypto import ed25519_pk_to_curve25519 from ..wallet.key_type import ( diff --git a/acapy_agent/didcomm_v2/tests/test_adapters.py b/acapy_agent/didcomm_v2/tests/test_adapters.py index 56d861bfcb..0157b84120 100644 --- a/acapy_agent/didcomm_v2/tests/test_adapters.py +++ b/acapy_agent/didcomm_v2/tests/test_adapters.py @@ -4,9 +4,7 @@ from ...config.injection_context import InjectionContext from ...core.event_bus import EventBus from ...core.protocol_registry import ProtocolRegistry -from ...protocols.coordinate_mediation.v1_0.route_manager import ( - RouteManager, -) +from ...protocols.coordinate_mediation.v1_0.route_manager import RouteManager from ...resolver.base import BaseDIDResolver from ...resolver.did_resolver import DIDResolver from ...tests.mock import AsyncMock, MagicMock diff --git a/acapy_agent/holder/tests/test_routes.py b/acapy_agent/holder/tests/test_routes.py index 615d350244..f5b05a7e30 100644 --- a/acapy_agent/holder/tests/test_routes.py +++ b/acapy_agent/holder/tests/test_routes.py @@ -293,7 +293,7 @@ async def test_credentials_remove_with_anoncreds(self, mock_delete_credential): ) ) - # Anoncreds holder errors + # AnonCreds holder errors mock_delete_credential.side_effect = [ None, AnonCredsHolderError("anoncreds error", error_code=AskarErrorCode.NOT_FOUND), diff --git a/acapy_agent/indy/credx/holder.py b/acapy_agent/indy/credx/holder.py index 31d4bb67d3..0beebe9b14 100644 --- a/acapy_agent/indy/credx/holder.py +++ b/acapy_agent/indy/credx/holder.py @@ -93,7 +93,7 @@ async def get_link_secret(self) -> LinkSecret: ms_string = record.value.decode("ascii") link_secret_dict = {"value": {"ms": ms_string}} secret = LinkSecret.load(link_secret_dict) - LOGGER.debug("Loaded LinkSecret from Anoncreds secret.") + LOGGER.debug("Loaded LinkSecret from AnonCreds secret.") except CredxError as decode_err: LOGGER.error("Error loading link secret: %s", decode_err) raise IndyHolderError("Error loading link secret") from err diff --git a/acapy_agent/indy/credx/tests/test_cred_issuance.py b/acapy_agent/indy/credx/tests/test_cred_issuance.py index f0154b0a7b..af815be6e2 100644 --- a/acapy_agent/indy/credx/tests/test_cred_issuance.py +++ b/acapy_agent/indy/credx/tests/test_cred_issuance.py @@ -5,9 +5,7 @@ import pytest from ....ledger.base import BaseLedger -from ....ledger.multiple_ledger.ledger_requests_executor import ( - IndyLedgerRequestsExecutor, -) +from ....ledger.multiple_ledger.ledger_requests_executor import IndyLedgerRequestsExecutor from ....tests import mock from ....utils.testing import create_test_profile from .. import holder, issuer, verifier diff --git a/acapy_agent/indy/models/tests/test_pres_preview.py b/acapy_agent/indy/models/tests/test_pres_preview.py index 2e7570a85f..7e89720bb7 100644 --- a/acapy_agent/indy/models/tests/test_pres_preview.py +++ b/acapy_agent/indy/models/tests/test_pres_preview.py @@ -5,9 +5,7 @@ import pytest -from ....ledger.multiple_ledger.ledger_requests_executor import ( - IndyLedgerRequestsExecutor, -) +from ....ledger.multiple_ledger.ledger_requests_executor import IndyLedgerRequestsExecutor from ....messaging.util import canon from ....multitenant.base import BaseMultitenantManager from ....multitenant.manager import MultitenantManager diff --git a/acapy_agent/indy/tests/test_verifier.py b/acapy_agent/indy/tests/test_verifier.py index 54762cb636..cd1c31d528 100644 --- a/acapy_agent/indy/tests/test_verifier.py +++ b/acapy_agent/indy/tests/test_verifier.py @@ -2,9 +2,7 @@ from time import time from unittest import IsolatedAsyncioTestCase -from ...ledger.multiple_ledger.ledger_requests_executor import ( - IndyLedgerRequestsExecutor, -) +from ...ledger.multiple_ledger.ledger_requests_executor import IndyLedgerRequestsExecutor from ...multitenant.base import BaseMultitenantManager from ...multitenant.manager import MultitenantManager from ...tests import mock diff --git a/acapy_agent/ledger/base.py b/acapy_agent/ledger/base.py index 20ed0718fa..0b671eb50c 100644 --- a/acapy_agent/ledger/base.py +++ b/acapy_agent/ledger/base.py @@ -622,9 +622,7 @@ async def send_schema_anoncreds( LedgerObjectAlreadyExistsError: If the schema already exists on the ledger. """ - from acapy_agent.anoncreds.default.legacy_indy.registry import ( - LegacyIndyRegistry, - ) + from acapy_agent.anoncreds.default.legacy_indy.registry import LegacyIndyRegistry public_info = await self.get_wallet_public_did() if not public_info: diff --git a/acapy_agent/ledger/multiple_ledger/indy_vdr_manager.py b/acapy_agent/ledger/multiple_ledger/indy_vdr_manager.py index 7664a620fc..4b34f24126 100644 --- a/acapy_agent/ledger/multiple_ledger/indy_vdr_manager.py +++ b/acapy_agent/ledger/multiple_ledger/indy_vdr_manager.py @@ -13,10 +13,7 @@ from ...ledger.error import LedgerError from ...wallet.crypto import did_is_self_certified from ..indy_vdr import IndyVdrLedger -from ..merkel_validation.domain_txn_handler import ( - get_proof_nodes, - prepare_for_state_read, -) +from ..merkel_validation.domain_txn_handler import get_proof_nodes, prepare_for_state_read from ..merkel_validation.trie import SubTrie from .base_manager import BaseMultipleLedgerManager, MultipleLedgerManagerError diff --git a/acapy_agent/ledger/tests/test_routes.py b/acapy_agent/ledger/tests/test_routes.py index d673ad857d..ffd58156dd 100644 --- a/acapy_agent/ledger/tests/test_routes.py +++ b/acapy_agent/ledger/tests/test_routes.py @@ -1,24 +1,22 @@ import json -import pytest import uuid -from marshmallow import ValidationError from typing import Optional from unittest import IsolatedAsyncioTestCase + +import pytest +from marshmallow import ValidationError from uuid_utils import uuid4 from ...connections.models.conn_record import ConnRecord from ...ledger.base import BaseLedger from ...ledger.endpoint_type import EndpointType from ...ledger.multiple_ledger.base_manager import BaseMultipleLedgerManager -from ...ledger.multiple_ledger.ledger_requests_executor import ( - IndyLedgerRequestsExecutor, -) from ...ledger.multiple_ledger.ledger_config_schema import ( ConfigurableWriteLedgersSchema, LedgerConfigInstanceSchema, LedgerConfigListSchema, ) - +from ...ledger.multiple_ledger.ledger_requests_executor import IndyLedgerRequestsExecutor from ...multitenant.base import BaseMultitenantManager from ...multitenant.manager import MultitenantManager from ...tests import mock diff --git a/acapy_agent/messaging/credential_definitions/tests/test_routes.py b/acapy_agent/messaging/credential_definitions/tests/test_routes.py index 65fb61e0b1..1d81ee188f 100644 --- a/acapy_agent/messaging/credential_definitions/tests/test_routes.py +++ b/acapy_agent/messaging/credential_definitions/tests/test_routes.py @@ -4,9 +4,7 @@ from ....connections.models.conn_record import ConnRecord from ....indy.issuer import IndyIssuer from ....ledger.base import BaseLedger -from ....ledger.multiple_ledger.ledger_requests_executor import ( - IndyLedgerRequestsExecutor, -) +from ....ledger.multiple_ledger.ledger_requests_executor import IndyLedgerRequestsExecutor from ....multitenant.base import BaseMultitenantManager from ....multitenant.manager import MultitenantManager from ....storage.base import BaseStorage diff --git a/acapy_agent/messaging/schemas/tests/test_routes.py b/acapy_agent/messaging/schemas/tests/test_routes.py index a84a05171d..1c097826b4 100644 --- a/acapy_agent/messaging/schemas/tests/test_routes.py +++ b/acapy_agent/messaging/schemas/tests/test_routes.py @@ -4,9 +4,7 @@ from ....connections.models.conn_record import ConnRecord from ....indy.issuer import IndyIssuer from ....ledger.base import BaseLedger -from ....ledger.multiple_ledger.ledger_requests_executor import ( - IndyLedgerRequestsExecutor, -) +from ....ledger.multiple_ledger.ledger_requests_executor import IndyLedgerRequestsExecutor from ....multitenant.base import BaseMultitenantManager from ....multitenant.manager import MultitenantManager from ....storage.base import BaseStorage diff --git a/acapy_agent/messaging/valid.py b/acapy_agent/messaging/valid.py index f1cb03544f..3b54bc01dc 100644 --- a/acapy_agent/messaging/valid.py +++ b/acapy_agent/messaging/valid.py @@ -362,7 +362,7 @@ def __init__(self): ) -class AnoncredsDID(Regexp): +class AnonCredsDID(Regexp): """Validate value against anoncreds DID.""" METHOD = r"([a-zA-Z0-9_]+)" @@ -482,7 +482,7 @@ def __init__(self): ) -class AnoncredsCredDefId(Regexp): +class AnonCredsCredDefId(Regexp): """Validate value against anoncreds credential definition identifier specification.""" EXAMPLE = "did:(method):3:CL:20:tag" @@ -492,7 +492,7 @@ def __init__(self): """Initialize the instance.""" super().__init__( - AnoncredsCredDefId.PATTERN, + AnonCredsCredDefId.PATTERN, error="Value {input} is not an anoncreds credential definition identifier", ) @@ -527,7 +527,7 @@ def __init__(self): ) -class AnoncredsSchemaId(Regexp): +class AnonCredsSchemaId(Regexp): """Validate value against indy schema identifier specification.""" EXAMPLE = "did:(method):2:schema_name:1.0" @@ -537,7 +537,7 @@ def __init__(self): """Initialize the instance.""" super().__init__( - AnoncredsSchemaId.PATTERN, + AnonCredsSchemaId.PATTERN, error="Value {input} is not an anoncreds schema identifier", ) @@ -562,7 +562,7 @@ def __init__(self): ) -class AnoncredsRevRegId(Regexp): +class AnonCredsRevRegId(Regexp): """Validate value against anoncreds revocation registry identifier specification.""" EXAMPLE = "did:(method):4:did::3:CL:20:tag:CL_ACCUM:0" @@ -572,7 +572,7 @@ def __init__(self): """Initialize the instance.""" super().__init__( - AnoncredsRevRegId.PATTERN, + AnonCredsRevRegId.PATTERN, error="Value {input} is not an anoncreds revocation registry identifier", ) @@ -1056,20 +1056,20 @@ def __init__( INDY_SCHEMA_ID_VALIDATE = IndySchemaId() INDY_SCHEMA_ID_EXAMPLE = IndySchemaId.EXAMPLE -ANONCREDS_SCHEMA_ID_VALIDATE = AnoncredsSchemaId() -ANONCREDS_SCHEMA_ID_EXAMPLE = AnoncredsSchemaId.EXAMPLE +ANONCREDS_SCHEMA_ID_VALIDATE = AnonCredsSchemaId() +ANONCREDS_SCHEMA_ID_EXAMPLE = AnonCredsSchemaId.EXAMPLE INDY_CRED_DEF_ID_VALIDATE = IndyCredDefId() INDY_CRED_DEF_ID_EXAMPLE = IndyCredDefId.EXAMPLE -ANONCREDS_CRED_DEF_ID_VALIDATE = AnoncredsCredDefId() -ANONCREDS_CRED_DEF_ID_EXAMPLE = AnoncredsCredDefId.EXAMPLE +ANONCREDS_CRED_DEF_ID_VALIDATE = AnonCredsCredDefId() +ANONCREDS_CRED_DEF_ID_EXAMPLE = AnonCredsCredDefId.EXAMPLE INDY_REV_REG_ID_VALIDATE = IndyRevRegId() INDY_REV_REG_ID_EXAMPLE = IndyRevRegId.EXAMPLE -ANONCREDS_REV_REG_ID_VALIDATE = AnoncredsRevRegId() -ANONCREDS_REV_REG_ID_EXAMPLE = AnoncredsRevRegId.EXAMPLE +ANONCREDS_REV_REG_ID_VALIDATE = AnonCredsRevRegId() +ANONCREDS_REV_REG_ID_EXAMPLE = AnonCredsRevRegId.EXAMPLE INDY_CRED_REV_ID_VALIDATE = IndyCredRevId() INDY_CRED_REV_ID_EXAMPLE = IndyCredRevId.EXAMPLE @@ -1140,5 +1140,5 @@ def __init__( INDY_OR_KEY_DID_VALIDATE = IndyOrKeyDID() INDY_OR_KEY_DID_EXAMPLE = IndyOrKeyDID.EXAMPLE -ANONCREDS_DID_VALIDATE = AnoncredsDID() -ANONCREDS_DID_EXAMPLE = AnoncredsDID.EXAMPLE +ANONCREDS_DID_VALIDATE = AnonCredsDID() +ANONCREDS_DID_EXAMPLE = AnonCredsDID.EXAMPLE diff --git a/acapy_agent/multitenant/manager.py b/acapy_agent/multitenant/manager.py index 1a6bda9030..9431e965f4 100644 --- a/acapy_agent/multitenant/manager.py +++ b/acapy_agent/multitenant/manager.py @@ -3,7 +3,7 @@ import logging from typing import Iterable, Optional -from ..askar.profile_anon import AskarAnoncredsProfile +from ..askar.profile_anon import AskarAnonCredsProfile from ..config.injection_context import InjectionContext from ..config.wallet import wallet_config from ..core.profile import Profile @@ -88,7 +88,7 @@ async def get_wallet_profile( # return anoncreds profile if explicitly set as wallet type if profile.context.settings.get("wallet.type") == "askar-anoncreds": - return AskarAnoncredsProfile( + return AskarAnonCredsProfile( profile.opened, profile.context, ) diff --git a/acapy_agent/multitenant/route_manager.py b/acapy_agent/multitenant/route_manager.py index 9369f34eb9..45653ba5f8 100644 --- a/acapy_agent/multitenant/route_manager.py +++ b/acapy_agent/multitenant/route_manager.py @@ -7,9 +7,7 @@ from ..core.profile import Profile from ..messaging.responder import BaseResponder from ..protocols.coordinate_mediation.v1_0.manager import MediationManager -from ..protocols.coordinate_mediation.v1_0.models.mediation_record import ( - MediationRecord, -) +from ..protocols.coordinate_mediation.v1_0.models.mediation_record import MediationRecord from ..protocols.coordinate_mediation.v1_0.normalization import ( normalize_from_did_key, normalize_to_did_key, diff --git a/acapy_agent/multitenant/single_wallet_askar_manager.py b/acapy_agent/multitenant/single_wallet_askar_manager.py index 56e9051a13..8294fcd779 100644 --- a/acapy_agent/multitenant/single_wallet_askar_manager.py +++ b/acapy_agent/multitenant/single_wallet_askar_manager.py @@ -3,7 +3,7 @@ from typing import Iterable, Optional, cast from ..askar.profile import AskarProfile -from ..askar.profile_anon import AskarAnoncredsProfile +from ..askar.profile_anon import AskarAnonCredsProfile from ..config.injection_context import InjectionContext from ..config.wallet import wallet_config from ..core.profile import Profile @@ -109,7 +109,7 @@ async def get_wallet_profile( # return anoncreds profile if explicitly set as wallet type if profile_context.settings.get("wallet.type") == "askar-anoncreds": - return AskarAnoncredsProfile( + return AskarAnonCredsProfile( self._multitenant_profile.opened, profile_context, profile_id=wallet_record.wallet_id, diff --git a/acapy_agent/multitenant/tests/test_route_manager.py b/acapy_agent/multitenant/tests/test_route_manager.py index 4dad3d9dce..245102e02d 100644 --- a/acapy_agent/multitenant/tests/test_route_manager.py +++ b/acapy_agent/multitenant/tests/test_route_manager.py @@ -2,9 +2,7 @@ from ...core.profile import Profile from ...messaging.responder import BaseResponder, MockResponder -from ...protocols.coordinate_mediation.v1_0.models.mediation_record import ( - MediationRecord, -) +from ...protocols.coordinate_mediation.v1_0.models.mediation_record import MediationRecord from ...protocols.coordinate_mediation.v1_0.route_manager import RouteManager from ...protocols.routing.v1_0.manager import RoutingManager from ...protocols.routing.v1_0.models.route_record import RouteRecord diff --git a/acapy_agent/multitenant/tests/test_single_wallet_askar_manager.py b/acapy_agent/multitenant/tests/test_single_wallet_askar_manager.py index 322a8517ec..a89412f430 100644 --- a/acapy_agent/multitenant/tests/test_single_wallet_askar_manager.py +++ b/acapy_agent/multitenant/tests/test_single_wallet_askar_manager.py @@ -123,11 +123,11 @@ async def test_get_anoncreds_wallet_profile_should_open_store_and_return_anoncre "acapy_agent.multitenant.single_wallet_askar_manager.wallet_config" ) as wallet_config, mock.patch( - "acapy_agent.multitenant.single_wallet_askar_manager.AskarAnoncredsProfile", - ) as AskarAnoncredsProfile, + "acapy_agent.multitenant.single_wallet_askar_manager.AskarAnonCredsProfile", + ) as AskarAnonCredsProfile, ): sub_wallet_profile_context = InjectionContext() - sub_wallet_profile = AskarAnoncredsProfile(None, None) + sub_wallet_profile = AskarAnonCredsProfile(None, None) sub_wallet_profile.context.copy.return_value = sub_wallet_profile_context def side_effect(context, provision): @@ -138,7 +138,7 @@ def side_effect(context, provision): await self.manager.get_wallet_profile(self.profile.context, wallet_record) - AskarAnoncredsProfile.assert_called_with( + AskarAnonCredsProfile.assert_called_with( sub_wallet_profile.opened, sub_wallet_profile_context, profile_id="test" ) diff --git a/acapy_agent/protocols/basicmessage/v1_0/messages/basicmessage.py b/acapy_agent/protocols/basicmessage/v1_0/messages/basicmessage.py index 1a8940a904..1688032759 100644 --- a/acapy_agent/protocols/basicmessage/v1_0/messages/basicmessage.py +++ b/acapy_agent/protocols/basicmessage/v1_0/messages/basicmessage.py @@ -7,10 +7,7 @@ from .....messaging.agent_message import AgentMessage, AgentMessageSchema from .....messaging.util import datetime_now, datetime_to_str -from .....messaging.valid import ( - ISO8601_DATETIME_EXAMPLE, - ISO8601_DATETIME_VALIDATE, -) +from .....messaging.valid import ISO8601_DATETIME_EXAMPLE, ISO8601_DATETIME_VALIDATE from ..message_types import BASIC_MESSAGE, PROTOCOL_PACKAGE HANDLER_CLASS = f"{PROTOCOL_PACKAGE}.handlers.basicmessage_handler.BasicMessageHandler" diff --git a/acapy_agent/protocols/coordinate_mediation/v1_0/messages/keylist.py b/acapy_agent/protocols/coordinate_mediation/v1_0/messages/keylist.py index e56484f831..a2c25a891c 100644 --- a/acapy_agent/protocols/coordinate_mediation/v1_0/messages/keylist.py +++ b/acapy_agent/protocols/coordinate_mediation/v1_0/messages/keylist.py @@ -7,10 +7,7 @@ from .....messaging.agent_message import AgentMessage, AgentMessageSchema from ..message_types import KEYLIST, PROTOCOL_PACKAGE from .inner.keylist_key import KeylistKeySchema -from .inner.keylist_query_paginate import ( - KeylistQueryPaginate, - KeylistQueryPaginateSchema, -) +from .inner.keylist_query_paginate import KeylistQueryPaginate, KeylistQueryPaginateSchema HANDLER_CLASS = f"{PROTOCOL_PACKAGE}.handlers.keylist_handler.KeylistHandler" diff --git a/acapy_agent/protocols/coordinate_mediation/v1_0/messages/keylist_query.py b/acapy_agent/protocols/coordinate_mediation/v1_0/messages/keylist_query.py index 64ed4f1fa1..c0d960638c 100644 --- a/acapy_agent/protocols/coordinate_mediation/v1_0/messages/keylist_query.py +++ b/acapy_agent/protocols/coordinate_mediation/v1_0/messages/keylist_query.py @@ -6,10 +6,7 @@ from .....messaging.agent_message import AgentMessage, AgentMessageSchema from ..message_types import KEYLIST_QUERY, PROTOCOL_PACKAGE -from .inner.keylist_query_paginate import ( - KeylistQueryPaginate, - KeylistQueryPaginateSchema, -) +from .inner.keylist_query_paginate import KeylistQueryPaginate, KeylistQueryPaginateSchema HANDLER_CLASS = f"{PROTOCOL_PACKAGE}.handlers.keylist_query_handler.KeylistQueryHandler" diff --git a/acapy_agent/protocols/coordinate_mediation/v1_0/route_manager_provider.py b/acapy_agent/protocols/coordinate_mediation/v1_0/route_manager_provider.py index 89368d3135..433e5ab945 100644 --- a/acapy_agent/protocols/coordinate_mediation/v1_0/route_manager_provider.py +++ b/acapy_agent/protocols/coordinate_mediation/v1_0/route_manager_provider.py @@ -3,10 +3,7 @@ from ....config.base import BaseInjector, BaseProvider, BaseSettings from ....core.profile import Profile from ....multitenant.base import BaseMultitenantManager -from ....multitenant.route_manager import ( - BaseWalletRouteManager, - MultitenantRouteManager, -) +from ....multitenant.route_manager import BaseWalletRouteManager, MultitenantRouteManager from .route_manager import CoordinateMediationV1RouteManager diff --git a/acapy_agent/protocols/coordinate_mediation/v1_0/routes.py b/acapy_agent/protocols/coordinate_mediation/v1_0/routes.py index 248777bc76..16e4a7cc5c 100644 --- a/acapy_agent/protocols/coordinate_mediation/v1_0/routes.py +++ b/acapy_agent/protocols/coordinate_mediation/v1_0/routes.py @@ -13,18 +13,15 @@ from ....admin.decorators.auth import tenant_authentication from ....admin.request_context import AdminRequestContext from ....connections.models.conn_record import ConnRecord +from ....connections.routes import ConnectionsConnIdMatchInfoSchema from ....messaging.models.base import BaseModelError from ....messaging.models.openapi import OpenAPISchema from ....messaging.valid import UUID4_EXAMPLE from ....storage.error import StorageError, StorageNotFoundError -from ....connections.routes import ConnectionsConnIdMatchInfoSchema from ...routing.v1_0.models.route_record import RouteRecord, RouteRecordSchema from .manager import MediationManager, MediationManagerError from .message_types import SPEC_URI -from .messages.inner.keylist_update_rule import ( - KeylistUpdateRule, - KeylistUpdateRuleSchema, -) +from .messages.inner.keylist_update_rule import KeylistUpdateRule, KeylistUpdateRuleSchema from .messages.keylist_query import KeylistQuerySchema from .messages.keylist_update import KeylistUpdateSchema from .messages.mediate_deny import MediationDenySchema diff --git a/acapy_agent/protocols/did_rotate/v1_0/manager.py b/acapy_agent/protocols/did_rotate/v1_0/manager.py index 684bb20dc6..c7bcae3b7d 100644 --- a/acapy_agent/protocols/did_rotate/v1_0/manager.py +++ b/acapy_agent/protocols/did_rotate/v1_0/manager.py @@ -3,10 +3,7 @@ Manages and tracks the state of the DID Rotate protocol. """ -from ....connections.base_manager import ( - BaseConnectionManager, - BaseConnectionManagerError, -) +from ....connections.base_manager import BaseConnectionManager, BaseConnectionManagerError from ....connections.models.conn_record import ConnRecord from ....core.profile import Profile from ....messaging.responder import BaseResponder diff --git a/acapy_agent/protocols/did_rotate/v1_0/messages/problem_report.py b/acapy_agent/protocols/did_rotate/v1_0/messages/problem_report.py index 35ce06213b..0d0a39b2f2 100644 --- a/acapy_agent/protocols/did_rotate/v1_0/messages/problem_report.py +++ b/acapy_agent/protocols/did_rotate/v1_0/messages/problem_report.py @@ -4,10 +4,7 @@ from marshmallow import EXCLUDE, ValidationError, pre_dump, validates_schema -from .....protocols.problem_report.v1_0.message import ( - ProblemReport, - ProblemReportSchema, -) +from .....protocols.problem_report.v1_0.message import ProblemReport, ProblemReportSchema from ..message_types import PROBLEM_REPORT, PROTOCOL_PACKAGE HANDLER_CLASS = f"{PROTOCOL_PACKAGE}.handlers.problem_report_handler.ProblemReportHandler" diff --git a/acapy_agent/protocols/didexchange/v1_0/manager.py b/acapy_agent/protocols/didexchange/v1_0/manager.py index 90df8daf17..39d1aaa637 100644 --- a/acapy_agent/protocols/didexchange/v1_0/manager.py +++ b/acapy_agent/protocols/didexchange/v1_0/manager.py @@ -7,10 +7,7 @@ from did_peer_4 import LONG_PATTERN, long_to_short from ....admin.server import AdminResponder -from ....connections.base_manager import ( - BaseConnectionManager, - BaseConnectionManagerError, -) +from ....connections.base_manager import BaseConnectionManager, BaseConnectionManagerError from ....connections.models.conn_record import ConnRecord from ....connections.models.connection_target import ConnectionTarget from ....core.error import BaseError diff --git a/acapy_agent/protocols/discovery/v1_0/routes.py b/acapy_agent/protocols/discovery/v1_0/routes.py index 04416b8045..3b1f42a305 100644 --- a/acapy_agent/protocols/discovery/v1_0/routes.py +++ b/acapy_agent/protocols/discovery/v1_0/routes.py @@ -12,10 +12,7 @@ from ....storage.error import StorageError, StorageNotFoundError from .manager import V10DiscoveryMgr from .message_types import SPEC_URI -from .models.discovery_record import ( - V10DiscoveryExchangeRecord, - V10DiscoveryRecordSchema, -) +from .models.discovery_record import V10DiscoveryExchangeRecord, V10DiscoveryRecordSchema class V10DiscoveryExchangeListResultSchema(OpenAPISchema): diff --git a/acapy_agent/protocols/discovery/v2_0/routes.py b/acapy_agent/protocols/discovery/v2_0/routes.py index bf2adb78b0..f6a0723c78 100644 --- a/acapy_agent/protocols/discovery/v2_0/routes.py +++ b/acapy_agent/protocols/discovery/v2_0/routes.py @@ -12,10 +12,7 @@ from ....storage.error import StorageError, StorageNotFoundError from .manager import V20DiscoveryMgr from .message_types import SPEC_URI -from .models.discovery_record import ( - V20DiscoveryExchangeRecord, - V20DiscoveryRecordSchema, -) +from .models.discovery_record import V20DiscoveryExchangeRecord, V20DiscoveryRecordSchema class V20DiscoveryExchangeResultSchema(OpenAPISchema): diff --git a/acapy_agent/protocols/introduction/v0_1/handlers/tests/test_forward_invitation_handler.py b/acapy_agent/protocols/introduction/v0_1/handlers/tests/test_forward_invitation_handler.py index c05f614d03..3bfc7a2ca3 100644 --- a/acapy_agent/protocols/introduction/v0_1/handlers/tests/test_forward_invitation_handler.py +++ b/acapy_agent/protocols/introduction/v0_1/handlers/tests/test_forward_invitation_handler.py @@ -4,9 +4,9 @@ from ......messaging.base_handler import HandlerException from ......messaging.request_context import RequestContext from ......messaging.responder import MockResponder -from .....out_of_band.v1_0.messages.invitation import InvitationMessage, Service from ......tests import mock from ......utils.testing import create_test_profile +from .....out_of_band.v1_0.messages.invitation import InvitationMessage, Service from ...messages.forward_invitation import ForwardInvitation from .. import forward_invitation_handler as test_module diff --git a/acapy_agent/protocols/introduction/v0_1/handlers/tests/test_invitation_handler.py b/acapy_agent/protocols/introduction/v0_1/handlers/tests/test_invitation_handler.py index e051a30b35..74c36b4d69 100644 --- a/acapy_agent/protocols/introduction/v0_1/handlers/tests/test_invitation_handler.py +++ b/acapy_agent/protocols/introduction/v0_1/handlers/tests/test_invitation_handler.py @@ -3,9 +3,9 @@ from ......messaging.base_handler import HandlerException from ......messaging.request_context import RequestContext from ......messaging.responder import MockResponder -from .....out_of_band.v1_0.messages.invitation import InvitationMessage, Service from ......tests import mock from ......utils.testing import create_test_profile +from .....out_of_band.v1_0.messages.invitation import InvitationMessage, Service from ...messages.invitation import Invitation from .. import invitation_handler as test_module diff --git a/acapy_agent/protocols/introduction/v0_1/handlers/tests/test_invitation_request_handler.py b/acapy_agent/protocols/introduction/v0_1/handlers/tests/test_invitation_request_handler.py index 1da593efb9..2afcbe1351 100644 --- a/acapy_agent/protocols/introduction/v0_1/handlers/tests/test_invitation_request_handler.py +++ b/acapy_agent/protocols/introduction/v0_1/handlers/tests/test_invitation_request_handler.py @@ -3,10 +3,10 @@ from ......messaging.base_handler import HandlerException from ......messaging.request_context import RequestContext from ......messaging.responder import MockResponder -from .....out_of_band.v1_0.messages.invitation import InvitationMessage, Service -from .....out_of_band.v1_0.models.invitation import InvitationRecord from ......tests import mock from ......utils.testing import create_test_profile +from .....out_of_band.v1_0.messages.invitation import InvitationMessage, Service +from .....out_of_band.v1_0.models.invitation import InvitationRecord from ...messages.invitation import Invitation from ...messages.invitation_request import InvitationRequest from .. import invitation_request_handler as test_module diff --git a/acapy_agent/protocols/issue_credential/v1_0/routes.py b/acapy_agent/protocols/issue_credential/v1_0/routes.py index d39893a2b0..6dc8ec793c 100644 --- a/acapy_agent/protocols/issue_credential/v1_0/routes.py +++ b/acapy_agent/protocols/issue_credential/v1_0/routes.py @@ -48,14 +48,8 @@ from .message_types import SPEC_URI from .messages.credential_problem_report import ProblemReportReason from .messages.credential_proposal import CredentialProposal, CredentialProposalSchema -from .messages.inner.credential_preview import ( - CredentialPreview, - CredentialPreviewSchema, -) -from .models.credential_exchange import ( - V10CredentialExchange, - V10CredentialExchangeSchema, -) +from .messages.inner.credential_preview import CredentialPreview, CredentialPreviewSchema +from .models.credential_exchange import V10CredentialExchange, V10CredentialExchangeSchema class IssueCredentialModuleResponseSchema(OpenAPISchema): diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/handler.py b/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/handler.py index 0836a7b4e2..c7079fd168 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/handler.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/handler.py @@ -10,18 +10,16 @@ from ......anoncreds.base import AnonCredsObjectNotFound, AnonCredsResolutionError from ......anoncreds.holder import AnonCredsHolder, AnonCredsHolderError from ......anoncreds.issuer import CATEGORY_CRED_DEF, AnonCredsIssuer -from ......anoncreds.models.credential import AnoncredsCredentialSchema -from ......anoncreds.models.credential_offer import AnoncredsCredentialOfferSchema +from ......anoncreds.models.credential import AnonCredsCredentialSchema +from ......anoncreds.models.credential_offer import AnonCredsCredentialOfferSchema from ......anoncreds.models.credential_proposal import ( - AnoncredsCredentialDefinitionProposal, + AnonCredsCredentialDefinitionProposal, ) -from ......anoncreds.models.credential_request import AnoncredsCredRequestSchema +from ......anoncreds.models.credential_request import AnonCredsCredRequestSchema from ......anoncreds.registry import AnonCredsRegistry from ......anoncreds.revocation import AnonCredsRevocation from ......cache.base import BaseCache -from ......messaging.credential_definitions.util import ( - CRED_DEF_SENT_RECORD_TYPE, -) +from ......messaging.credential_definitions.util import CRED_DEF_SENT_RECORD_TYPE from ......messaging.decorators.attach_decorator import AttachDecorator from ......revocation_anoncreds.models.issuer_cred_rev_record import IssuerCredRevRecord from ......storage.base import BaseStorage @@ -38,14 +36,14 @@ from ...messages.cred_proposal import V20CredProposal from ...messages.cred_request import V20CredRequest from ...models.cred_ex_record import V20CredExRecord -from ...models.detail.anoncreds import V20CredExRecordAnoncreds +from ...models.detail.anoncreds import V20CredExRecordAnonCreds from ..handler import CredFormatAttachment, V20CredFormatError, V20CredFormatHandler LOGGER = logging.getLogger(__name__) class AnonCredsCredFormatHandler(V20CredFormatHandler): - """Anoncreds credential format handler.""" + """AnonCreds credential format handler.""" format = V20CredFormat.Format.ANONCREDS @@ -69,10 +67,10 @@ def validate_fields(cls, message_type: str, attachment_data: Mapping): """ mapping = { - CRED_20_PROPOSAL: AnoncredsCredentialDefinitionProposal, - CRED_20_OFFER: AnoncredsCredentialOfferSchema, - CRED_20_REQUEST: AnoncredsCredRequestSchema, - CRED_20_ISSUE: AnoncredsCredentialSchema, + CRED_20_PROPOSAL: AnonCredsCredentialDefinitionProposal, + CRED_20_OFFER: AnonCredsCredentialOfferSchema, + CRED_20_REQUEST: AnonCredsCredRequestSchema, + CRED_20_ISSUE: AnonCredsCredentialSchema, } # Get schema class @@ -81,7 +79,7 @@ def validate_fields(cls, message_type: str, attachment_data: Mapping): # Validate, throw if not valid Schema(unknown=RAISE).load(attachment_data) - async def get_detail_record(self, cred_ex_id: str) -> V20CredExRecordAnoncreds: + async def get_detail_record(self, cred_ex_id: str) -> V20CredExRecordAnonCreds: """Retrieve credential exchange detail record by cred_ex_id.""" async with self.profile.session() as session: @@ -285,7 +283,7 @@ async def create_request( """Create anoncreds credential request.""" if cred_ex_record.state != V20CredExRecord.STATE_OFFER_RECEIVED: raise V20CredFormatError( - "Anoncreds issue credential format cannot start from credential request" + "AnonCreds issue credential format cannot start from credential request" ) await self._check_uniqueness(cred_ex_record.cred_ex_id) @@ -339,7 +337,7 @@ async def _create(): if not cred_req_result: cred_req_result = await _create() - detail_record = V20CredExRecordAnoncreds( + detail_record = V20CredExRecordAnonCreds( cred_ex_id=cred_ex_record.cred_ex_id, cred_request_metadata=cred_req_result["metadata"], ) @@ -355,7 +353,7 @@ async def receive_request( """Receive anoncreds credential request.""" if not cred_ex_record.cred_offer: raise V20CredFormatError( - "Anoncreds issue credential format cannot start from credential request" + "AnonCreds issue credential format cannot start from credential request" ) async def issue_credential( @@ -396,7 +394,7 @@ async def issue_credential( result = self.get_format_data(CRED_20_ISSUE, json.loads(cred_json)) async with self._profile.transaction() as txn: - detail_record = V20CredExRecordAnoncreds( + detail_record = V20CredExRecordAnonCreds( cred_ex_id=cred_ex_record.cred_ex_id, rev_reg_id=rev_reg_def_id, cred_rev_id=cred_rev_id, diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/tests/test_handler.py b/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/tests/test_handler.py index 48bb244191..665fb90eb4 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/tests/test_handler.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/tests/test_handler.py @@ -45,7 +45,7 @@ from ....messages.cred_request import V20CredRequest from ....messages.inner.cred_preview import V20CredAttrSpec, V20CredPreview from ....models.cred_ex_record import V20CredExRecord -from ....models.detail.anoncreds import V20CredExRecordAnoncreds +from ....models.detail.anoncreds import V20CredExRecordAnonCreds from ...handler import V20CredFormatError from .. import handler as test_module from ..handler import LOGGER as ANONCREDS_LOGGER @@ -221,7 +221,7 @@ async def asyncSetUp(self): self.holder = mock.MagicMock(AnonCredsHolder, autospec=True) self.profile.context.injector.bind_instance(AnonCredsHolder, self.holder) - # Anoncreds registry + # AnonCreds registry self.profile.context.injector.bind_instance( AnonCredsRegistry, AnonCredsRegistry() ) @@ -289,12 +289,12 @@ async def test_validate_fields(self): async def test_get_indy_detail_record(self): cred_ex_id = "dummy" details_indy = [ - V20CredExRecordAnoncreds( + V20CredExRecordAnonCreds( cred_ex_id=cred_ex_id, rev_reg_id="rr-id", cred_rev_id="0", ), - V20CredExRecordAnoncreds( + V20CredExRecordAnonCreds( cred_ex_id=cred_ex_id, rev_reg_id="rr-id", cred_rev_id="1", @@ -482,7 +482,7 @@ async def test_create_offer(self): ) ) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_create_offer_no_cache(self): schema_id_parts = SCHEMA_ID.split(":") @@ -545,7 +545,7 @@ async def test_create_offer_no_cache(self): # assert data is encoded as base64 assert attachment.data.base64 - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_create_offer_attr_mismatch(self): schema_id_parts = SCHEMA_ID.split(":") @@ -602,7 +602,7 @@ async def test_create_offer_attr_mismatch(self): with self.assertRaises(V20CredFormatError): await self.handler.create_offer(cred_proposal) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_create_offer_no_matching_sent_cred_def(self): cred_proposal = V20CredProposal( formats=[ @@ -631,7 +631,7 @@ async def test_receive_offer(self): # Not much to assert. Receive offer doesn't do anything await self.handler.receive_offer(cred_ex_record, cred_offer_message) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_create_request(self): holder_did = "did" @@ -701,7 +701,7 @@ async def test_create_request_bad_state(self): with self.assertRaises(V20CredFormatError) as context: await self.handler.create_request(cred_ex_record) assert ( - "Anoncreds issue credential format cannot start from credential request" + "AnonCreds issue credential format cannot start from credential request" in str(context.exception) ) @@ -710,7 +710,7 @@ async def test_create_request_bad_state(self): with self.assertRaises(V20CredFormatError) as context: await self.handler.create_request(cred_ex_record) assert ( - "Anoncreds issue credential format cannot start from credential request" + "AnonCreds issue credential format cannot start from credential request" in str(context.exception) ) @@ -744,11 +744,11 @@ async def test_receive_request_no_offer(self): await self.handler.receive_request(cred_ex_record, cred_request_message) assert ( - "Anoncreds issue credential format cannot start from credential request" + "AnonCreds issue credential format cannot start from credential request" in str(context.exception) ) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_issue_credential_revocable(self): attr_values = { "legalName": "value", @@ -834,7 +834,7 @@ async def test_issue_credential_revocable(self): # assert data is encoded as base64 assert attachment.data.base64 - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_issue_credential_non_revocable(self): CRED_DEF_NR = deepcopy(CRED_DEF) CRED_DEF_NR["value"]["revocation"] = None @@ -933,7 +933,7 @@ async def test_issue_credential_not_unique_x(self): assert "indy detail record already exists" in str(context.exception) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_issue_credential_no_active_rr_no_retries(self): attr_values = { "legalName": "value", @@ -992,7 +992,7 @@ async def test_issue_credential_no_active_rr_no_retries(self): await self.handler.issue_credential(cred_ex_record, retries=0) assert "has no active revocation registry" in str(context.exception) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_issue_credential_no_active_rr_retry(self): attr_values = { "legalName": "value", @@ -1064,7 +1064,7 @@ async def test_issue_credential_no_active_rr_retry(self): await self.handler.issue_credential(cred_ex_record, retries=1) assert "has no active revocation registry" in str(context.exception) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_issue_credential_rr_full(self): attr_values = { "legalName": "value", @@ -1137,7 +1137,7 @@ async def test_receive_credential(self): # Not much to assert. Receive credential doesn't do anything await self.handler.receive_credential(cred_ex_record, cred_issue_message) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_store_credential(self): connection_id = "test_conn_id" attr_values = { @@ -1264,7 +1264,7 @@ async def test_store_credential(self): rev_reg_def=REV_REG_DEF, ) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_store_credential_holder_store_indy_error(self): connection_id = "test_conn_id" attr_values = { diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/indy/handler.py b/acapy_agent/protocols/issue_credential/v2_0/formats/indy/handler.py index a1888f317d..c177b40b4f 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/indy/handler.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/indy/handler.py @@ -7,7 +7,7 @@ from marshmallow import RAISE -from ......askar.profile_anon import AskarAnoncredsProfile +from ......askar.profile_anon import AskarAnonCredsProfile from ......cache.base import BaseCache from ......core.profile import Profile from ......indy.holder import IndyHolder, IndyHolderError @@ -207,7 +207,7 @@ async def create_offer( ) -> CredFormatAttachment: """Create indy credential offer.""" - if isinstance(self.profile, AskarAnoncredsProfile): + if isinstance(self.profile, AskarAnonCredsProfile): raise V20CredFormatError( "This issuer is anoncreds capable. Please use the anoncreds format." ) diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/ld_proof/tests/test_handler.py b/acapy_agent/protocols/issue_credential/v2_0/formats/ld_proof/tests/test_handler.py index b72e1175bd..a534c266b2 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/ld_proof/tests/test_handler.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/ld_proof/tests/test_handler.py @@ -44,10 +44,10 @@ from ..handler import LDProofCredFormatHandler from ..models.cred_detail import LDProofVCDetail from .fixtures import ( + LD_PROOF_VC, LD_PROOF_VC_DETAIL, LD_PROOF_VC_DETAIL_BBS, LD_PROOF_VC_DETAIL_ED25519_2020, - LD_PROOF_VC, ) diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/handler.py b/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/handler.py index 3412cc93b8..d9c6fa763a 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/handler.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/handler.py @@ -48,14 +48,14 @@ from ..handler import CredFormatAttachment, V20CredFormatError, V20CredFormatHandler from .models.cred import VCDIIndyCredentialSchema from .models.cred_offer import ( - AnoncredsLinkSecret, + AnonCredsLinkSecret, BindingMethod, DidcommSignedAttachment, VCDICredAbstract, VCDICredAbstractSchema, ) from .models.cred_request import ( - AnoncredsLinkSecretRequest, + AnonCredsLinkSecretRequest, BindingProof, DidcommSignedAttachmentRequest, VCDICredRequest, @@ -262,7 +262,7 @@ async def _create(): issuance_date=datetime.datetime.now(datetime.timezone.utc).isoformat(), ) - anoncreds_link_secret_instance = AnoncredsLinkSecret( + anoncreds_link_secret_instance = AnonCredsLinkSecret( cred_def_id=cred_offer["cred_def_id"], key_correctness_proof=cred_offer["key_correctness_proof"], nonce=cred_offer["nonce"], @@ -380,7 +380,7 @@ async def _create(): entropy = cred_req_result["request"]["prover_did"] else: entropy = cred_req_result["request"]["entropy"] - anoncreds_link_secret_instance = AnoncredsLinkSecretRequest( + anoncreds_link_secret_instance = AnonCredsLinkSecretRequest( entropy=entropy, cred_def_id=cred_req_result["request"]["cred_def_id"], blinded_ms=cred_req_result["request"]["blinded_ms"], diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/models/cred_offer.py b/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/models/cred_offer.py index 7c278cd82a..95ecc2d67b 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/models/cred_offer.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/models/cred_offer.py @@ -15,13 +15,13 @@ from .......vc.vc_ld.models.credential import CredentialSchema, VerifiableCredential -class AnoncredsLinkSecret(BaseModel): - """Anoncreds Link Secret Model.""" +class AnonCredsLinkSecret(BaseModel): + """AnonCreds Link Secret Model.""" class Meta: - """AnoncredsLinkSecret metadata.""" + """AnonCredsLinkSecret metadata.""" - schema_class = "AnoncredsLinkSecretSchema" + schema_class = "AnonCredsLinkSecretSchema" def __init__( self, @@ -30,20 +30,20 @@ def __init__( key_correctness_proof: Optional[str] = None, **kwargs, ): - """Initialize values for AnoncredsLinkSecret.""" + """Initialize values for AnonCredsLinkSecret.""" super().__init__(**kwargs) self.nonce = nonce self.cred_def_id = cred_def_id self.key_correctness_proof = key_correctness_proof -class AnoncredsLinkSecretSchema(BaseModelSchema): - """Anoncreds Link Secret Schema.""" +class AnonCredsLinkSecretSchema(BaseModelSchema): + """AnonCreds Link Secret Schema.""" class Meta: - """AnoncredsLinkSecret schema metadata.""" + """AnonCredsLinkSecret schema metadata.""" - model_class = AnoncredsLinkSecret + model_class = AnonCredsLinkSecret unknown = EXCLUDE nonce = fields.Str( @@ -126,7 +126,7 @@ class Meta: def __init__( self, - anoncreds_link_secret: Union[dict, AnoncredsLinkSecret] = None, + anoncreds_link_secret: Union[dict, AnonCredsLinkSecret] = None, didcomm_signed_attachment: Union[dict, DidcommSignedAttachment] = None, **kwargs, ): @@ -145,7 +145,7 @@ class Meta: model_class = BindingMethod unknown = EXCLUDE - anoncreds_link_secret = fields.Nested(AnoncredsLinkSecretSchema, required=False) + anoncreds_link_secret = fields.Nested(AnonCredsLinkSecretSchema, required=False) didcomm_signed_attachment = fields.Nested( DidcommSignedAttachmentSchema, required=True ) diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/models/cred_request.py b/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/models/cred_request.py index 0c47e51e6e..203182d9e7 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/models/cred_request.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/models/cred_request.py @@ -14,7 +14,7 @@ ) -class AnoncredsLinkSecretRequest(BaseModel): +class AnonCredsLinkSecretRequest(BaseModel): """Binding proof model.""" class Meta: @@ -40,13 +40,13 @@ def __init__( self.nonce = nonce -class AnoncredsLinkSecretSchema(BaseModelSchema): +class AnonCredsLinkSecretSchema(BaseModelSchema): """VCDI credential request schema.""" class Meta: """VCDI credential request schema metadata.""" - model_class = AnoncredsLinkSecretRequest + model_class = AnonCredsLinkSecretRequest unknown = EXCLUDE entropy = fields.Str( @@ -135,7 +135,7 @@ class Meta: unknown = EXCLUDE anoncreds_link_secret = fields.Nested( - AnoncredsLinkSecretSchema(), + AnonCredsLinkSecretSchema(), required=True, metadata={"description": "", "example": ""}, ) diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/tests/test_handler.py b/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/tests/test_handler.py index 3ff75a5119..9192bc92f4 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/tests/test_handler.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/tests/test_handler.py @@ -9,14 +9,8 @@ from .......anoncreds.holder import AnonCredsHolder, AnonCredsHolderError from .......anoncreds.issuer import AnonCredsIssuer -from .......anoncreds.models.credential_definition import ( - CredDef, - GetCredDefResult, -) -from .......anoncreds.models.revocation import ( - GetRevRegDefResult, - RevRegDef, -) +from .......anoncreds.models.credential_definition import CredDef, GetCredDefResult +from .......anoncreds.models.revocation import GetRevRegDefResult, RevRegDef from .......anoncreds.registry import AnonCredsRegistry from .......cache.base import BaseCache from .......cache.in_memory import InMemoryCache @@ -30,24 +24,16 @@ from .......multitenant.manager import MultitenantManager from .......protocols.issue_credential.v2_0.formats.handler import V20CredFormatError from .......protocols.issue_credential.v2_0.messages.cred_format import V20CredFormat -from .......protocols.issue_credential.v2_0.messages.cred_issue import ( - V20CredIssue, -) +from .......protocols.issue_credential.v2_0.messages.cred_issue import V20CredIssue from .......protocols.issue_credential.v2_0.messages.cred_offer import V20CredOffer -from .......protocols.issue_credential.v2_0.messages.cred_proposal import ( - V20CredProposal, -) +from .......protocols.issue_credential.v2_0.messages.cred_proposal import V20CredProposal from .......protocols.issue_credential.v2_0.messages.cred_request import V20CredRequest from .......protocols.issue_credential.v2_0.messages.inner.cred_preview import ( V20CredAttrSpec, V20CredPreview, ) -from .......protocols.issue_credential.v2_0.models.cred_ex_record import ( - V20CredExRecord, -) -from .......protocols.issue_credential.v2_0.models.detail.indy import ( - V20CredExRecordIndy, -) +from .......protocols.issue_credential.v2_0.models.cred_ex_record import V20CredExRecord +from .......protocols.issue_credential.v2_0.models.detail.indy import V20CredExRecordIndy from .......storage.base import BaseStorage from .......storage.record import StorageRecord from .......tests import mock @@ -460,7 +446,7 @@ async def test_create_offer(self, _): # self.issuer.create_credential_offer.assert_not_called() - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_receive_offer(self): cred_ex_record = mock.MagicMock() cred_offer_message = mock.MagicMock() @@ -558,7 +544,7 @@ async def test_create_request(self): cred_ex_record, {"holder_did": holder_did} ) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_receive_request(self): cred_ex_record = mock.MagicMock() cred_request_message = mock.MagicMock() @@ -643,7 +629,7 @@ async def test_issue_credential_revocable(self): assert attachment.data.base64 assert attachment.content == {"credential": VCDI_CRED} - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_issue_credential_non_revocable(self): CRED_DEF_NR = deepcopy(CRED_DEF) CRED_DEF_NR["value"]["revocation"] = None diff --git a/acapy_agent/protocols/issue_credential/v2_0/messages/cred_format.py b/acapy_agent/protocols/issue_credential/v2_0/messages/cred_format.py index 589dfcf579..9593dc2a57 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/messages/cred_format.py +++ b/acapy_agent/protocols/issue_credential/v2_0/messages/cred_format.py @@ -11,7 +11,7 @@ from .....messaging.models.base import BaseModel, BaseModelSchema from .....messaging.valid import UUID4_EXAMPLE from .....utils.classloader import DeferLoad -from ..models.detail.anoncreds import V20CredExRecordAnoncreds +from ..models.detail.anoncreds import V20CredExRecordAnonCreds from ..models.detail.indy import V20CredExRecordIndy from ..models.detail.ld_proof import V20CredExRecordLDProof @@ -34,7 +34,7 @@ class Format(Enum): ANONCREDS = FormatSpec( "anoncreds/", - V20CredExRecordAnoncreds, + V20CredExRecordAnonCreds, DeferLoad( "acapy_agent.protocols.issue_credential.v2_0" ".formats.anoncreds.handler.AnonCredsCredFormatHandler" @@ -91,7 +91,7 @@ def aries(self) -> str: @property def detail( self, - ) -> Union[V20CredExRecordIndy, V20CredExRecordLDProof, V20CredExRecordAnoncreds]: + ) -> Union[V20CredExRecordIndy, V20CredExRecordLDProof, V20CredExRecordAnonCreds]: """Accessor for credential exchange detail class.""" return self.value.detail diff --git a/acapy_agent/protocols/issue_credential/v2_0/models/detail/anoncreds.py b/acapy_agent/protocols/issue_credential/v2_0/models/detail/anoncreds.py index f683ff68ca..cc751633fc 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/models/detail/anoncreds.py +++ b/acapy_agent/protocols/issue_credential/v2_0/models/detail/anoncreds.py @@ -1,4 +1,4 @@ -"""Anoncreds specific credential exchange information with non-secrets storage.""" +"""AnonCreds specific credential exchange information with non-secrets storage.""" from typing import Any, Mapping, Optional, Sequence @@ -14,13 +14,13 @@ from .. import UNENCRYPTED_TAGS -class V20CredExRecordAnoncreds(BaseRecord): +class V20CredExRecordAnonCreds(BaseRecord): """Credential exchange anoncreds detail record.""" class Meta: - """V20CredExRecordAnoncreds metadata.""" + """V20CredExRecordAnonCreds metadata.""" - schema_class = "V20CredExRecordAnoncredsSchema" + schema_class = "V20CredExRecordAnonCredsSchema" RECORD_ID_NAME = "cred_ex_anoncreds_id" RECORD_TYPE = "anoncreds_cred_ex_v20" @@ -70,7 +70,7 @@ async def query_by_cred_ex_id( cls, session: ProfileSession, cred_ex_id: str, - ) -> Sequence["V20CredExRecordAnoncreds"]: + ) -> Sequence["V20CredExRecordAnonCreds"]: """Retrieve credential exchange anoncreds detail record(s) by its cred ex id.""" return await cls.query( session=session, @@ -82,13 +82,13 @@ def __eq__(self, other: Any) -> bool: return super().__eq__(other) -class V20CredExRecordAnoncredsSchema(BaseRecordSchema): +class V20CredExRecordAnonCredsSchema(BaseRecordSchema): """Credential exchange anoncreds detail record detail schema.""" class Meta: """Credential exchange anoncreds detail record schema metadata.""" - model_class = V20CredExRecordAnoncreds + model_class = V20CredExRecordAnonCreds unknown = EXCLUDE cred_ex_anoncreds_id = fields.Str( diff --git a/acapy_agent/protocols/issue_credential/v2_0/routes.py b/acapy_agent/protocols/issue_credential/v2_0/routes.py index c7c73b1c35..c9f21f03da 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/routes.py +++ b/acapy_agent/protocols/issue_credential/v2_0/routes.py @@ -138,8 +138,8 @@ class V20CredStoreRequestSchema(OpenAPISchema): credential_id = fields.Str(required=False) -class V20CredFilterAnoncredsSchema(OpenAPISchema): - """Anoncreds credential filtration criteria.""" +class V20CredFilterAnonCredsSchema(OpenAPISchema): + """AnonCreds credential filtration criteria.""" schema_issuer_id = fields.Str( required=False, @@ -272,7 +272,7 @@ class V20CredFilterSchema(OpenAPISchema): """Credential filtration criteria.""" anoncreds = fields.Nested( - V20CredFilterAnoncredsSchema, + V20CredFilterAnonCredsSchema, required=False, metadata={"description": "Credential filter for anoncreds"}, ) diff --git a/acapy_agent/protocols/issue_credential/v2_0/tests/test_routes.py b/acapy_agent/protocols/issue_credential/v2_0/tests/test_routes.py index 8691862f0d..37025d27b4 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/tests/test_routes.py +++ b/acapy_agent/protocols/issue_credential/v2_0/tests/test_routes.py @@ -2,9 +2,7 @@ from .....admin.request_context import AdminRequestContext from .....connections.models.conn_record import ConnRecord -from .....protocols.issue_credential.v2_0.models.cred_ex_record import ( - V20CredExRecord, -) +from .....protocols.issue_credential.v2_0.models.cred_ex_record import V20CredExRecord from .....tests import mock from .....utils.testing import create_test_profile from .....vc.ld_proofs.error import LinkedDataProofException diff --git a/acapy_agent/protocols/out_of_band/v1_0/manager.py b/acapy_agent/protocols/out_of_band/v1_0/manager.py index cef2b07e9a..b3b06d4d05 100644 --- a/acapy_agent/protocols/out_of_band/v1_0/manager.py +++ b/acapy_agent/protocols/out_of_band/v1_0/manager.py @@ -21,7 +21,7 @@ from ....storage.error import StorageNotFoundError from ....transport.inbound.receipt import MessageReceipt from ....wallet.base import BaseWallet -from ....wallet.did_info import DIDInfo, INVITATION_REUSE_KEY +from ....wallet.did_info import INVITATION_REUSE_KEY, DIDInfo from ....wallet.did_method import PEER2, PEER4 from ....wallet.error import WalletNotFoundError from ....wallet.key_type import ED25519 diff --git a/acapy_agent/protocols/out_of_band/v1_0/tests/test_manager.py b/acapy_agent/protocols/out_of_band/v1_0/tests/test_manager.py index 739edb73ff..af73556bd7 100644 --- a/acapy_agent/protocols/out_of_band/v1_0/tests/test_manager.py +++ b/acapy_agent/protocols/out_of_band/v1_0/tests/test_manager.py @@ -1,14 +1,13 @@ """Test OOB Manager.""" import base64 +import json from copy import deepcopy from datetime import datetime, timedelta, timezone -import json from typing import List from unittest import IsolatedAsyncioTestCase from unittest.mock import ANY -from .. import manager as test_module from .....connections.models.conn_record import ConnRecord from .....connections.models.connection_target import ConnectionTarget from .....connections.models.diddoc import DIDDoc, PublicKey, PublicKeyType, Service @@ -57,9 +56,7 @@ V20CredAttrSpec, V20CredPreview, ) -from ....present_proof.v1_0.message_types import ( - ATTACH_DECO_IDS as V10_PRES_ATTACH_FORMAT, -) +from ....present_proof.v1_0.message_types import ATTACH_DECO_IDS as V10_PRES_ATTACH_FORMAT from ....present_proof.v1_0.message_types import PRESENTATION_REQUEST from ....present_proof.v1_0.messages.presentation_request import PresentationRequest from ....present_proof.v2_0.message_types import ( @@ -68,11 +65,12 @@ from ....present_proof.v2_0.message_types import PRES_20_REQUEST from ....present_proof.v2_0.messages.pres_format import V20PresFormat from ....present_proof.v2_0.messages.pres_request import V20PresRequest +from .. import manager as test_module from ..manager import ( - OutOfBandManager, - OutOfBandManagerError, REUSE_ACCEPTED_WEBHOOK_TOPIC, REUSE_WEBHOOK_TOPIC, + OutOfBandManager, + OutOfBandManagerError, ) from ..messages.invitation import HSProto, InvitationMessage from ..messages.invitation import Service as OobService diff --git a/acapy_agent/protocols/present_proof/anoncreds/pres_exch_handler.py b/acapy_agent/protocols/present_proof/anoncreds/pres_exch_handler.py index 039f335ef1..e95f5827d7 100644 --- a/acapy_agent/protocols/present_proof/anoncreds/pres_exch_handler.py +++ b/acapy_agent/protocols/present_proof/anoncreds/pres_exch_handler.py @@ -12,7 +12,7 @@ from ....anoncreds.models.utils import extract_non_revocation_intervals_from_proof_request from ....anoncreds.registry import AnonCredsRegistry from ....anoncreds.revocation import AnonCredsRevocation -from ....askar.profile_anon import AskarAnoncredsProfile +from ....askar.profile_anon import AskarAnonCredsProfile from ....core.error import BaseError from ....core.profile import Profile from ..v1_0.models.presentation_exchange import V10PresentationExchange @@ -23,7 +23,7 @@ class AnonCredsPresExchHandlerError(BaseError): - """Base class for Anoncreds Presentation Exchange related errors.""" + """Base class for AnonCreds Presentation Exchange related errors.""" class AnonCredsPresExchHandler: @@ -233,11 +233,11 @@ async def return_presentation( pres_ex_record: Union[V10PresentationExchange, V20PresExRecord], requested_credentials: Optional[dict] = None, ) -> dict: - """Return Anoncreds proof request as dict.""" + """Return AnonCreds proof request as dict.""" # If not anoncreds capable, try to use indy handler. This should be removed when # indy filter is completely retired - if not isinstance(self._profile, AskarAnoncredsProfile): + if not isinstance(self._profile, AskarAnonCredsProfile): from ..indy.pres_exch_handler import IndyPresExchHandler handler = IndyPresExchHandler(self._profile) diff --git a/acapy_agent/protocols/present_proof/dif/pres_exch_handler.py b/acapy_agent/protocols/present_proof/dif/pres_exch_handler.py index 5641aaefc9..388ef06f64 100644 --- a/acapy_agent/protocols/present_proof/dif/pres_exch_handler.py +++ b/acapy_agent/protocols/present_proof/dif/pres_exch_handler.py @@ -29,9 +29,9 @@ BbsBlsSignature2020, BbsBlsSignatureProof2020, DocumentLoader, + EcdsaSecp256r1Signature2019, Ed25519Signature2018, Ed25519Signature2020, - EcdsaSecp256r1Signature2019, WalletKeyPair, ) from ....vc.ld_proofs.constants import ( diff --git a/acapy_agent/protocols/present_proof/v1_0/models/presentation_exchange.py b/acapy_agent/protocols/present_proof/v1_0/models/presentation_exchange.py index 7732de5997..72a1fcc4d1 100644 --- a/acapy_agent/protocols/present_proof/v1_0/models/presentation_exchange.py +++ b/acapy_agent/protocols/present_proof/v1_0/models/presentation_exchange.py @@ -15,10 +15,7 @@ PresentationProposal, PresentationProposalSchema, ) -from ..messages.presentation_request import ( - PresentationRequest, - PresentationRequestSchema, -) +from ..messages.presentation_request import PresentationRequest, PresentationRequestSchema from ..messages.presentation_webhook import V10PresentationExchangeWebhook from . import UNENCRYPTED_TAGS diff --git a/acapy_agent/protocols/present_proof/v1_0/tests/test_routes.py b/acapy_agent/protocols/present_proof/v1_0/tests/test_routes.py index 28c7930443..4e45688df3 100644 --- a/acapy_agent/protocols/present_proof/v1_0/tests/test_routes.py +++ b/acapy_agent/protocols/present_proof/v1_0/tests/test_routes.py @@ -5,7 +5,7 @@ from .....admin.request_context import AdminRequestContext from .....anoncreds.models.presentation_request import ( - AnoncredsPresentationReqAttrSpecSchema, + AnonCredsPresentationReqAttrSpecSchema, ) from .....indy.holder import IndyHolder from .....indy.verifier import IndyVerifier @@ -37,7 +37,7 @@ async def asyncSetUp(self): ) async def test_validate_proof_req_attr_spec(self): - aspec = AnoncredsPresentationReqAttrSpecSchema() + aspec = AnonCredsPresentationReqAttrSpecSchema() aspec.validate_fields({"name": "attr0"}) aspec.validate_fields( { diff --git a/acapy_agent/protocols/present_proof/v2_0/formats/anoncreds/handler.py b/acapy_agent/protocols/present_proof/v2_0/formats/anoncreds/handler.py index 492d0f3c4b..e4d40fed0a 100644 --- a/acapy_agent/protocols/present_proof/v2_0/formats/anoncreds/handler.py +++ b/acapy_agent/protocols/present_proof/v2_0/formats/anoncreds/handler.py @@ -8,8 +8,8 @@ from ......anoncreds.holder import AnonCredsHolder from ......anoncreds.models.predicate import Predicate -from ......anoncreds.models.presentation_request import AnoncredsPresentationRequestSchema -from ......anoncreds.models.proof import AnoncredsProofSchema +from ......anoncreds.models.presentation_request import AnonCredsPresentationRequestSchema +from ......anoncreds.models.proof import AnonCredsProofSchema from ......anoncreds.models.utils import get_requested_creds_from_proof_request_preview from ......anoncreds.registry import AnonCredsRegistry from ......anoncreds.util import generate_pr_nonce @@ -17,12 +17,7 @@ from ......messaging.decorators.attach_decorator import AttachDecorator from ......messaging.util import canon from ....anoncreds.pres_exch_handler import AnonCredsPresExchHandler -from ...message_types import ( - ATTACHMENT_FORMAT, - PRES_20, - PRES_20_PROPOSAL, - PRES_20_REQUEST, -) +from ...message_types import ATTACHMENT_FORMAT, PRES_20, PRES_20_PROPOSAL, PRES_20_REQUEST from ...messages.pres import V20Pres from ...messages.pres_format import V20PresFormat from ...models.pres_exchange import V20PresExRecord @@ -32,7 +27,7 @@ class AnonCredsPresExchangeHandler(V20PresFormatHandler): - """Anoncreds presentation format handler.""" + """AnonCreds presentation format handler.""" format = V20PresFormat.Format.ANONCREDS @@ -56,9 +51,9 @@ def validate_fields(cls, message_type: str, attachment_data: Mapping): """ mapping = { - PRES_20_REQUEST: AnoncredsPresentationRequestSchema, - PRES_20_PROPOSAL: AnoncredsPresentationRequestSchema, - PRES_20: AnoncredsProofSchema, + PRES_20_REQUEST: AnonCredsPresentationRequestSchema, + PRES_20_PROPOSAL: AnonCredsPresentationRequestSchema, + PRES_20: AnonCredsProofSchema, } # Get schema class diff --git a/acapy_agent/protocols/present_proof/v2_0/formats/dif/handler.py b/acapy_agent/protocols/present_proof/v2_0/formats/dif/handler.py index d0b60321bd..206a4fc658 100644 --- a/acapy_agent/protocols/present_proof/v2_0/formats/dif/handler.py +++ b/acapy_agent/protocols/present_proof/v2_0/formats/dif/handler.py @@ -13,9 +13,9 @@ from ......storage.vc_holder.vc_record import VCRecord from ......vc.ld_proofs import ( BbsBlsSignature2020, + EcdsaSecp256r1Signature2019, Ed25519Signature2018, Ed25519Signature2020, - EcdsaSecp256r1Signature2019, ) from ......vc.vc_di.manager import VcDiManager from ......vc.vc_ld.manager import VcLdpManager @@ -28,12 +28,7 @@ from ....dif.pres_request_schema import DIFPresSpecSchema, DIFProofRequestSchema from ....dif.pres_schema import DIFProofSchema from ....v2_0.messages.pres_problem_report import ProblemReportReason -from ...message_types import ( - ATTACHMENT_FORMAT, - PRES_20, - PRES_20_PROPOSAL, - PRES_20_REQUEST, -) +from ...message_types import ATTACHMENT_FORMAT, PRES_20, PRES_20_PROPOSAL, PRES_20_REQUEST from ...messages.pres import V20Pres from ...messages.pres_format import V20PresFormat from ...models.pres_exchange import V20PresExRecord diff --git a/acapy_agent/protocols/present_proof/v2_0/formats/indy/handler.py b/acapy_agent/protocols/present_proof/v2_0/formats/indy/handler.py index 2400b60213..23744d0651 100644 --- a/acapy_agent/protocols/present_proof/v2_0/formats/indy/handler.py +++ b/acapy_agent/protocols/present_proof/v2_0/formats/indy/handler.py @@ -17,12 +17,7 @@ from ......messaging.decorators.attach_decorator import AttachDecorator from ......messaging.util import canon from ....indy.pres_exch_handler import IndyPresExchHandler -from ...message_types import ( - ATTACHMENT_FORMAT, - PRES_20, - PRES_20_PROPOSAL, - PRES_20_REQUEST, -) +from ...message_types import ATTACHMENT_FORMAT, PRES_20, PRES_20_PROPOSAL, PRES_20_REQUEST from ...messages.pres import V20Pres from ...messages.pres_format import V20PresFormat from ...models.pres_exchange import V20PresExRecord diff --git a/acapy_agent/protocols/present_proof/v2_0/routes.py b/acapy_agent/protocols/present_proof/v2_0/routes.py index 5839f0a4a6..5204a552d7 100644 --- a/acapy_agent/protocols/present_proof/v2_0/routes.py +++ b/acapy_agent/protocols/present_proof/v2_0/routes.py @@ -17,8 +17,8 @@ from ....admin.decorators.auth import tenant_authentication from ....admin.request_context import AdminRequestContext from ....anoncreds.holder import AnonCredsHolder, AnonCredsHolderError -from ....anoncreds.models.presentation_request import AnoncredsPresentationRequestSchema -from ....anoncreds.models.proof import AnoncredsPresSpecSchema +from ....anoncreds.models.presentation_request import AnonCredsPresentationRequestSchema +from ....anoncreds.models.proof import AnonCredsPresSpecSchema from ....connections.models.conn_record import ConnRecord from ....indy.holder import IndyHolder, IndyHolderError from ....indy.models.cred_precis import IndyCredPrecisSchema @@ -61,12 +61,7 @@ from . import problem_report_for_record, report_problem from .formats.handler import V20PresFormatHandlerError from .manager import V20PresManager -from .message_types import ( - ATTACHMENT_FORMAT, - PRES_20_PROPOSAL, - PRES_20_REQUEST, - SPEC_URI, -) +from .message_types import ATTACHMENT_FORMAT, PRES_20_PROPOSAL, PRES_20_REQUEST, SPEC_URI from .messages.pres_format import V20PresFormat from .messages.pres_problem_report import ProblemReportReason from .messages.pres_proposal import V20PresProposal @@ -126,7 +121,7 @@ class V20PresProposalByFormatSchema(OpenAPISchema): """Schema for presentation proposal per format.""" anoncreds = fields.Nested( - AnoncredsPresentationRequestSchema, + AnonCredsPresentationRequestSchema, required=False, metadata={"description": "Presentation proposal for anoncreds"}, ) @@ -205,7 +200,7 @@ class V20PresRequestByFormatSchema(OpenAPISchema): """Presentation request per format.""" anoncreds = fields.Nested( - AnoncredsPresentationRequestSchema, + AnonCredsPresentationRequestSchema, required=False, metadata={"description": "Presentation proposal for anoncreds"}, ) @@ -312,7 +307,7 @@ class V20PresSpecByFormatRequestSchema(AdminAPIMessageTracingSchema): """Presentation specification schema by format, for send-presentation request.""" anoncreds = fields.Nested( - AnoncredsPresSpecSchema, + AnonCredsPresSpecSchema, required=False, metadata={"description": "Presentation specification for anoncreds"}, ) diff --git a/acapy_agent/protocols/present_proof/v2_0/tests/test_manager.py b/acapy_agent/protocols/present_proof/v2_0/tests/test_manager.py index ccc823dabf..91e535fea7 100644 --- a/acapy_agent/protocols/present_proof/v2_0/tests/test_manager.py +++ b/acapy_agent/protocols/present_proof/v2_0/tests/test_manager.py @@ -33,12 +33,7 @@ from ..formats.handler import V20PresFormatHandlerError from ..formats.indy import handler as test_indy_handler from ..manager import V20PresManager, V20PresManagerError -from ..message_types import ( - ATTACHMENT_FORMAT, - PRES_20, - PRES_20_PROPOSAL, - PRES_20_REQUEST, -) +from ..message_types import ATTACHMENT_FORMAT, PRES_20, PRES_20_PROPOSAL, PRES_20_REQUEST from ..messages.pres import V20Pres from ..messages.pres_format import V20PresFormat from ..messages.pres_problem_report import V20PresProblemReport diff --git a/acapy_agent/protocols/present_proof/v2_0/tests/test_manager_anoncreds.py b/acapy_agent/protocols/present_proof/v2_0/tests/test_manager_anoncreds.py index a836e55ab3..b2d14f8fd0 100644 --- a/acapy_agent/protocols/present_proof/v2_0/tests/test_manager_anoncreds.py +++ b/acapy_agent/protocols/present_proof/v2_0/tests/test_manager_anoncreds.py @@ -43,12 +43,7 @@ from ..formats.handler import V20PresFormatHandlerError from ..formats.indy import handler as test_indy_handler from ..manager import V20PresManager, V20PresManagerError -from ..message_types import ( - ATTACHMENT_FORMAT, - PRES_20, - PRES_20_PROPOSAL, - PRES_20_REQUEST, -) +from ..message_types import ATTACHMENT_FORMAT, PRES_20, PRES_20_PROPOSAL, PRES_20_REQUEST from ..messages.pres import V20Pres from ..messages.pres_format import V20PresFormat from ..messages.pres_problem_report import V20PresProblemReport @@ -809,7 +804,7 @@ async def test_receive_pres_request(self): assert px_rec_out.state == V20PresExRecord.STATE_REQUEST_RECEIVED - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_create_pres_indy(self): pres_request = V20PresRequest( formats=[ @@ -859,7 +854,7 @@ async def test_create_pres_indy(self): save_ex.assert_called_once() assert px_rec_out.state == V20PresExRecord.STATE_PRESENTATION_SENT - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_create_pres_indy_and_dif(self): pres_request = V20PresRequest( formats=[ @@ -924,7 +919,7 @@ async def test_create_pres_indy_and_dif(self): save_ex.assert_called_once() assert px_rec_out.state == V20PresExRecord.STATE_PRESENTATION_SENT - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_create_pres_proof_req_non_revoc_interval_none(self): indy_proof_req_vcx = deepcopy(ANONCREDS_PROOF_REQ_NAME) indy_proof_req_vcx["non_revoked"] = None # simulate interop with indy-vcx @@ -986,7 +981,7 @@ async def test_create_pres_proof_req_non_revoc_interval_none(self): save_ex.assert_called_once() assert px_rec_out.state == V20PresExRecord.STATE_PRESENTATION_SENT - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_create_pres_self_asserted(self): pres_request = V20PresRequest( formats=[ @@ -1038,7 +1033,7 @@ async def test_create_pres_self_asserted(self): save_ex.assert_called_once() assert px_rec_out.state == V20PresExRecord.STATE_PRESENTATION_SENT - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_create_pres_no_revocation(self): self.ledger = mock.MagicMock(BaseLedger, autospec=True) self.ledger.get_schema = mock.CoroutineMock(return_value=mock.MagicMock()) @@ -1132,7 +1127,7 @@ async def test_create_pres_no_revocation(self): await self.manager.create_pres(px_rec_in, request_data) mock_log_info.assert_called_once() - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_create_pres_bad_revoc_state(self): pres_request = V20PresRequest( formats=[ @@ -1206,7 +1201,7 @@ async def test_create_pres_bad_revoc_state(self): with self.assertRaises(test_indy_util_module.AnonCredsHolderError): await self.manager.create_pres(px_rec_in, request_data) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_create_pres_multi_matching_proposal_creds_names(self): pres_request = V20PresRequest( formats=[ @@ -1380,7 +1375,7 @@ async def test_no_matching_creds_indy_handler(self): (px_rec_out, pres_msg) = await self.manager.create_pres( px_rec_in, request_data ) - assert "AnonCreds interface requires AskarAnoncreds profile" in str( + assert "AnonCreds interface requires AskarAnonCreds profile" in str( context.exception ) @@ -2178,7 +2173,7 @@ async def test_receive_pres_bait_and_switch_pred(self): context.exception ) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_verify_pres(self): pres_request = V20PresRequest( formats=[ @@ -2228,7 +2223,7 @@ async def test_verify_pres(self): assert px_rec_out.state == (V20PresExRecord.STATE_DONE) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_verify_pres_indy_and_dif(self): pres_request = V20PresRequest( formats=[ diff --git a/acapy_agent/protocols/present_proof/v2_0/tests/test_routes.py b/acapy_agent/protocols/present_proof/v2_0/tests/test_routes.py index 7d120b0052..14a4441b8e 100644 --- a/acapy_agent/protocols/present_proof/v2_0/tests/test_routes.py +++ b/acapy_agent/protocols/present_proof/v2_0/tests/test_routes.py @@ -7,7 +7,7 @@ from .....admin.request_context import AdminRequestContext from .....anoncreds.models.presentation_request import ( - AnoncredsPresentationReqAttrSpecSchema, + AnonCredsPresentationReqAttrSpecSchema, ) from .....indy.holder import IndyHolder from .....indy.verifier import IndyVerifier @@ -223,7 +223,7 @@ async def test_validate(self): schema.validate_fields({"veres-one": {"no": "support"}}) async def test_validate_proof_req_attr_spec(self): - aspec = AnoncredsPresentationReqAttrSpecSchema() + aspec = AnonCredsPresentationReqAttrSpecSchema() aspec.validate_fields({"name": "attr0"}) aspec.validate_fields( { diff --git a/acapy_agent/protocols/present_proof/v2_0/tests/test_routes_anoncreds.py b/acapy_agent/protocols/present_proof/v2_0/tests/test_routes_anoncreds.py index 4a29ff2b08..ec3e3e6932 100644 --- a/acapy_agent/protocols/present_proof/v2_0/tests/test_routes_anoncreds.py +++ b/acapy_agent/protocols/present_proof/v2_0/tests/test_routes_anoncreds.py @@ -9,7 +9,7 @@ from .....admin.request_context import AdminRequestContext from .....anoncreds.holder import AnonCredsHolder from .....anoncreds.models.presentation_request import ( - AnoncredsPresentationReqAttrSpecSchema, + AnonCredsPresentationReqAttrSpecSchema, ) from .....anoncreds.verifier import AnonCredsVerifier from .....ledger.base import BaseLedger @@ -225,7 +225,7 @@ async def test_validate(self): schema.validate_fields({"veres-one": {"no": "support"}}) async def test_validate_proof_req_attr_spec(self): - aspec = AnoncredsPresentationReqAttrSpecSchema() + aspec = AnonCredsPresentationReqAttrSpecSchema() aspec.validate_fields({"name": "attr0"}) aspec.validate_fields( { @@ -307,7 +307,7 @@ async def test_present_proof_credentials_list_not_found(self): with self.assertRaises(test_module.web.HTTPNotFound): await test_module.present_proof_credentials_list(self.request) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_present_proof_credentials_x(self): self.request.match_info = { "pres_ex_id": "123-456-789", @@ -334,7 +334,7 @@ async def test_present_proof_credentials_x(self): with self.assertRaises(test_module.web.HTTPBadRequest): await test_module.present_proof_credentials_list(self.request) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_present_proof_credentials_list_single_referent(self): self.request.match_info = { "pres_ex_id": "123-456-789", @@ -367,7 +367,7 @@ async def test_present_proof_credentials_list_single_referent(self): await test_module.present_proof_credentials_list(self.request) mock_response.assert_called_once_with(returned_credentials) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_present_proof_credentials_list_multiple_referents(self): self.request.match_info = { "pres_ex_id": "123-456-789", diff --git a/acapy_agent/protocols/routing/v1_0/handlers/forward_handler.py b/acapy_agent/protocols/routing/v1_0/handlers/forward_handler.py index 78cbbd6114..c86a4fedbb 100644 --- a/acapy_agent/protocols/routing/v1_0/handlers/forward_handler.py +++ b/acapy_agent/protocols/routing/v1_0/handlers/forward_handler.py @@ -2,13 +2,13 @@ import json +from .....connections.base_manager import BaseConnectionManager from .....messaging.base_handler import ( BaseHandler, BaseResponder, HandlerException, RequestContext, ) -from .....connections.base_manager import BaseConnectionManager from ..manager import RoutingManager, RoutingManagerError from ..messages.forward import Forward diff --git a/acapy_agent/resolver/default/peer4.py b/acapy_agent/resolver/default/peer4.py index 6407bd4e5a..4b0ecfc9fb 100644 --- a/acapy_agent/resolver/default/peer4.py +++ b/acapy_agent/resolver/default/peer4.py @@ -6,13 +6,7 @@ from re import compile from typing import Optional, Pattern, Sequence, Text -from did_peer_4 import ( - LONG_PATTERN, - SHORT_PATTERN, - long_to_short, - resolve, - resolve_short, -) +from did_peer_4 import LONG_PATTERN, SHORT_PATTERN, long_to_short, resolve, resolve_short from ...config.injection_context import InjectionContext from ...core.profile import Profile diff --git a/acapy_agent/resolver/default/tests/test_indy.py b/acapy_agent/resolver/default/tests/test_indy.py index cf0ba77d5b..a2d89b8a4a 100644 --- a/acapy_agent/resolver/default/tests/test_indy.py +++ b/acapy_agent/resolver/default/tests/test_indy.py @@ -5,9 +5,7 @@ from ....core.profile import Profile from ....ledger.base import BaseLedger from ....ledger.error import LedgerError -from ....ledger.multiple_ledger.ledger_requests_executor import ( - IndyLedgerRequestsExecutor, -) +from ....ledger.multiple_ledger.ledger_requests_executor import IndyLedgerRequestsExecutor from ....messaging.valid import IndyDID from ....multitenant.base import BaseMultitenantManager from ....multitenant.manager import MultitenantManager diff --git a/acapy_agent/revocation/manager.py b/acapy_agent/revocation/manager.py index be5de7cd1d..e1e2a3de7d 100644 --- a/acapy_agent/revocation/manager.py +++ b/acapy_agent/revocation/manager.py @@ -17,9 +17,7 @@ TransactionManager, TransactionManagerError, ) -from ..protocols.endorse_transaction.v1_0.util import ( - get_endorser_connection_id, -) +from ..protocols.endorse_transaction.v1_0.util import get_endorser_connection_id from ..protocols.issue_credential.v1_0.models.credential_exchange import ( V10CredentialExchange, ) diff --git a/acapy_agent/revocation/routes.py b/acapy_agent/revocation/routes.py index 6f1427861e..7bac4b06a6 100644 --- a/acapy_agent/revocation/routes.py +++ b/acapy_agent/revocation/routes.py @@ -62,10 +62,7 @@ from .error import RevocationError, RevocationNotSupportedError from .indy import IndyRevocation from .manager import RevocationManager, RevocationManagerError -from .models.issuer_cred_rev_record import ( - IssuerCredRevRecord, - IssuerCredRevRecordSchema, -) +from .models.issuer_cred_rev_record import IssuerCredRevRecord, IssuerCredRevRecordSchema from .models.issuer_rev_reg_record import IssuerRevRegRecord, IssuerRevRegRecordSchema from .util import ( REVOCATION_ENTRY_EVENT, diff --git a/acapy_agent/revocation/tests/test_indy.py b/acapy_agent/revocation/tests/test_indy.py index 8925d90699..4cc3f6153a 100644 --- a/acapy_agent/revocation/tests/test_indy.py +++ b/acapy_agent/revocation/tests/test_indy.py @@ -1,9 +1,7 @@ from unittest import IsolatedAsyncioTestCase from ...ledger.base import BaseLedger -from ...ledger.multiple_ledger.ledger_requests_executor import ( - IndyLedgerRequestsExecutor, -) +from ...ledger.multiple_ledger.ledger_requests_executor import IndyLedgerRequestsExecutor from ...multitenant.base import BaseMultitenantManager from ...multitenant.manager import MultitenantManager from ...storage.error import StorageNotFoundError diff --git a/acapy_agent/revocation/tests/test_manager.py b/acapy_agent/revocation/tests/test_manager.py index 2334724614..fdf9518439 100644 --- a/acapy_agent/revocation/tests/test_manager.py +++ b/acapy_agent/revocation/tests/test_manager.py @@ -14,9 +14,7 @@ V10CredentialExchange, ) from ...protocols.issue_credential.v2_0.models.cred_ex_record import V20CredExRecord -from ...revocation.models.issuer_cred_rev_record import ( - IssuerCredRevRecord, -) +from ...revocation.models.issuer_cred_rev_record import IssuerCredRevRecord from ...tests import mock from ...utils.testing import create_test_profile from .. import manager as test_module diff --git a/acapy_agent/revocation_anoncreds/models/issuer_cred_rev_record.py b/acapy_agent/revocation_anoncreds/models/issuer_cred_rev_record.py index 84a9dcc81b..469f1a46fc 100644 --- a/acapy_agent/revocation_anoncreds/models/issuer_cred_rev_record.py +++ b/acapy_agent/revocation_anoncreds/models/issuer_cred_rev_record.py @@ -15,7 +15,7 @@ class IssuerCredRevRecord(BaseRecord): class Meta: """IssuerCredRevRecord metadata.""" - schema_class = "IssuerCredRevRecordSchemaAnoncreds" + schema_class = "IssuerCredRevRecordSchemaAnonCreds" RECORD_TYPE = "issuer_cred_rev" RECORD_ID_NAME = "record_id" @@ -121,7 +121,7 @@ def __eq__(self, other: Any) -> bool: return super().__eq__(other) -class IssuerCredRevRecordSchemaAnoncreds(BaseRecordSchema): +class IssuerCredRevRecordSchemaAnonCreds(BaseRecordSchema): """Schema to allow de/serialization of credential revocation records.""" class Meta: diff --git a/acapy_agent/revocation_anoncreds/routes.py b/acapy_agent/revocation_anoncreds/routes.py index 145074ab29..c89c929818 100644 --- a/acapy_agent/revocation_anoncreds/routes.py +++ b/acapy_agent/revocation_anoncreds/routes.py @@ -27,12 +27,12 @@ from ..anoncreds.models.revocation import RevRegDefState from ..anoncreds.revocation import AnonCredsRevocation, AnonCredsRevocationError from ..anoncreds.routes import ( + AnonCredsRevocationModuleResponseSchema, + AnonCredsRevRegIdMatchInfoSchema, create_transaction_for_endorser_description, endorser_connection_id_description, - AnonCredsRevRegIdMatchInfoSchema, - AnoncredsRevocationModuleResponseSchema, ) -from ..askar.profile_anon import AskarAnoncredsProfile +from ..askar.profile_anon import AskarAnonCredsProfile from ..indy.issuer import IndyIssuerError from ..indy.models.revocation import IndyRevRegDef from ..ledger.base import BaseLedger @@ -62,15 +62,15 @@ from .manager import RevocationManager, RevocationManagerError from .models.issuer_cred_rev_record import ( IssuerCredRevRecord, - IssuerCredRevRecordSchemaAnoncreds, + IssuerCredRevRecordSchemaAnonCreds, ) LOGGER = logging.getLogger(__name__) -TAG_TITLE = "anoncreds - revocation" +TAG_TITLE = "AnonCreds - Revocation" -class RevRegResultSchemaAnoncreds(OpenAPISchema): +class RevRegResultSchemaAnonCreds(OpenAPISchema): """Result schema for revocation registry creation request.""" result = fields.Nested(IssuerRevRegRecordSchema()) @@ -152,19 +152,19 @@ def validate_fields(self, data, **kwargs): ) -class CredRevRecordResultSchemaAnoncreds(OpenAPISchema): +class CredRevRecordResultSchemaAnonCreds(OpenAPISchema): """Result schema for credential revocation record request.""" - result = fields.Nested(IssuerCredRevRecordSchemaAnoncreds()) + result = fields.Nested(IssuerCredRevRecordSchemaAnonCreds()) -class CredRevRecordDetailsResultSchemaAnoncreds(OpenAPISchema): +class CredRevRecordDetailsResultSchemaAnonCreds(OpenAPISchema): """Result schema for credential revocation record request.""" - results = fields.List(fields.Nested(IssuerCredRevRecordSchemaAnoncreds())) + results = fields.List(fields.Nested(IssuerCredRevRecordSchemaAnonCreds())) -class CredRevIndyRecordsResultSchemaAnoncreds(OpenAPISchema): +class CredRevIndyRecordsResultSchemaAnonCreds(OpenAPISchema): """Result schema for revoc reg delta.""" rev_reg_delta = fields.Dict( @@ -172,7 +172,7 @@ class CredRevIndyRecordsResultSchemaAnoncreds(OpenAPISchema): ) -class RevRegIssuedResultSchemaAnoncreds(OpenAPISchema): +class RevRegIssuedResultSchemaAnonCreds(OpenAPISchema): """Result schema for revocation registry credentials issued request.""" result = fields.Int( @@ -194,7 +194,7 @@ class RevRegUpdateRequestMatchInfoSchema(OpenAPISchema): ) -class RevRegWalletUpdatedResultSchemaAnoncreds(OpenAPISchema): +class RevRegWalletUpdatedResultSchemaAnonCreds(OpenAPISchema): """Number of wallet revocation entries status updated.""" rev_reg_delta = fields.Dict( @@ -208,7 +208,7 @@ class RevRegWalletUpdatedResultSchemaAnoncreds(OpenAPISchema): ) -class RevRegsCreatedSchemaAnoncreds(OpenAPISchema): +class RevRegsCreatedSchemaAnonCreds(OpenAPISchema): """Result schema for request for revocation registries created.""" rev_reg_ids = fields.List( @@ -328,7 +328,7 @@ class PublishRevocationsOptions(OpenAPISchema): ) -class PublishRevocationsSchemaAnoncreds(OpenAPISchema): +class PublishRevocationsSchemaAnonCreds(OpenAPISchema): """Request and result schema for revocation publication API call.""" rrid2crid = fields.Dict( @@ -348,7 +348,7 @@ class PublishRevocationsSchemaAnoncreds(OpenAPISchema): options = fields.Nested(PublishRevocationsOptions()) -class PublishRevocationsResultSchemaAnoncreds(OpenAPISchema): +class PublishRevocationsResultSchemaAnonCreds(OpenAPISchema): """Result schema for credential definition send request.""" rrid2crid = fields.Dict( @@ -367,7 +367,7 @@ class PublishRevocationsResultSchemaAnoncreds(OpenAPISchema): ) -class RevokeRequestSchemaAnoncreds(CredRevRecordQueryStringSchema): +class RevokeRequestSchemaAnonCreds(CredRevRecordQueryStringSchema): """Parameters and validators for revocation request.""" @validates_schema @@ -439,8 +439,8 @@ def validate_fields(self, data, **kwargs): tags=[TAG_TITLE], summary="Revoke an issued credential", ) -@request_schema(RevokeRequestSchemaAnoncreds()) -@response_schema(AnoncredsRevocationModuleResponseSchema(), description="") +@request_schema(RevokeRequestSchemaAnonCreds()) +@response_schema(AnonCredsRevocationModuleResponseSchema(), description="") @tenant_authentication async def revoke(request: web.BaseRequest): """Request handler for storing a credential revocation. @@ -493,8 +493,8 @@ async def revoke(request: web.BaseRequest): @docs(tags=[TAG_TITLE], summary="Publish pending revocations to ledger") -@request_schema(PublishRevocationsSchemaAnoncreds()) -@response_schema(PublishRevocationsResultSchemaAnoncreds(), 200, description="") +@request_schema(PublishRevocationsSchemaAnonCreds()) +@response_schema(PublishRevocationsResultSchemaAnonCreds(), 200, description="") @tenant_authentication async def publish_revocations(request: web.BaseRequest): """Request handler for publishing pending revocations to the ledger. @@ -534,7 +534,7 @@ async def publish_revocations(request: web.BaseRequest): summary="Search for matching revocation registries that current agent created", ) @querystring_schema(RevRegsCreatedQueryStringSchema()) -@response_schema(RevRegsCreatedSchemaAnoncreds(), 200, description="") +@response_schema(RevRegsCreatedSchemaAnonCreds(), 200, description="") @tenant_authentication async def get_rev_regs(request: web.BaseRequest): """Request handler to get revocation registries that current agent created. @@ -571,7 +571,7 @@ async def get_rev_regs(request: web.BaseRequest): summary="Get revocation registry by revocation registry id", ) @match_info_schema(AnonCredsRevRegIdMatchInfoSchema()) -@response_schema(RevRegResultSchemaAnoncreds(), 200, description="") +@response_schema(RevRegResultSchemaAnonCreds(), 200, description="") @tenant_authentication async def get_rev_reg(request: web.BaseRequest): """Request handler to get a revocation registry by rev reg id. @@ -595,7 +595,7 @@ async def get_rev_reg(request: web.BaseRequest): async def _get_issuer_rev_reg_record( - profile: AskarAnoncredsProfile, rev_reg_id + profile: AskarAnonCredsProfile, rev_reg_id ) -> IssuerRevRegRecord: # fetch rev reg def from anoncreds try: @@ -646,7 +646,7 @@ async def _get_issuer_rev_reg_record( summary="Get current active revocation registry by credential definition id", ) @match_info_schema(RevocationCredDefIdMatchInfoSchema()) -@response_schema(RevRegResultSchemaAnoncreds(), 200, description="") +@response_schema(RevRegResultSchemaAnonCreds(), 200, description="") @tenant_authentication async def get_active_rev_reg(request: web.BaseRequest): """Request handler to get current active revocation registry by cred def id. @@ -676,7 +676,7 @@ async def get_active_rev_reg(request: web.BaseRequest): @docs(tags=[TAG_TITLE], summary="Rotate revocation registry") @match_info_schema(RevocationCredDefIdMatchInfoSchema()) -@response_schema(RevRegsCreatedSchemaAnoncreds(), 200, description="") +@response_schema(RevRegsCreatedSchemaAnonCreds(), 200, description="") @tenant_authentication async def rotate_rev_reg(request: web.BaseRequest): """Request handler to rotate the active revocation registries for cred. def. @@ -709,7 +709,7 @@ async def rotate_rev_reg(request: web.BaseRequest): summary="Get number of credentials issued against revocation registry", ) @match_info_schema(AnonCredsRevRegIdMatchInfoSchema()) -@response_schema(RevRegIssuedResultSchemaAnoncreds(), 200, description="") +@response_schema(RevRegIssuedResultSchemaAnonCreds(), 200, description="") @tenant_authentication async def get_rev_reg_issued_count(request: web.BaseRequest): """Request handler to get number of credentials issued against revocation registry. @@ -750,7 +750,7 @@ async def get_rev_reg_issued_count(request: web.BaseRequest): summary="Get details of credentials issued against revocation registry", ) @match_info_schema(AnonCredsRevRegIdMatchInfoSchema()) -@response_schema(CredRevRecordDetailsResultSchemaAnoncreds(), 200, description="") +@response_schema(CredRevRecordDetailsResultSchemaAnonCreds(), 200, description="") @tenant_authentication async def get_rev_reg_issued(request: web.BaseRequest): """Request handler to get credentials issued against revocation registry. @@ -792,7 +792,7 @@ async def get_rev_reg_issued(request: web.BaseRequest): summary="Get details of revoked credentials from ledger", ) @match_info_schema(AnonCredsRevRegIdMatchInfoSchema()) -@response_schema(CredRevIndyRecordsResultSchemaAnoncreds(), 200, description="") +@response_schema(CredRevIndyRecordsResultSchemaAnonCreds(), 200, description="") @tenant_authentication async def get_rev_reg_indy_recs(request: web.BaseRequest): """Request handler to get details of revoked credentials from ledger. @@ -838,7 +838,7 @@ async def get_rev_reg_indy_recs(request: web.BaseRequest): ) @match_info_schema(AnonCredsRevRegIdMatchInfoSchema()) @querystring_schema(RevRegUpdateRequestMatchInfoSchema()) -@response_schema(RevRegWalletUpdatedResultSchemaAnoncreds(), 200, description="") +@response_schema(RevRegWalletUpdatedResultSchemaAnonCreds(), 200, description="") @tenant_authentication async def update_rev_reg_revoked_state(request: web.BaseRequest): """Request handler to fix ledger entry of credentials revoked against registry. @@ -935,7 +935,7 @@ async def update_rev_reg_revoked_state(request: web.BaseRequest): summary="Get credential revocation status", ) @querystring_schema(CredRevRecordQueryStringSchema()) -@response_schema(CredRevRecordResultSchemaAnoncreds(), 200, description="") +@response_schema(CredRevRecordResultSchemaAnonCreds(), 200, description="") @tenant_authentication async def get_cred_rev_record(request: web.BaseRequest): """Request handler to get credential revocation record. @@ -978,7 +978,7 @@ async def get_cred_rev_record(request: web.BaseRequest): produces=["application/octet-stream"], ) @match_info_schema(AnonCredsRevRegIdMatchInfoSchema()) -@response_schema(AnoncredsRevocationModuleResponseSchema, description="tails file") +@response_schema(AnonCredsRevocationModuleResponseSchema, description="tails file") @tenant_authentication async def get_tails_file(request: web.BaseRequest) -> web.FileResponse: """Request handler to download tails file for revocation registry. @@ -1017,7 +1017,7 @@ async def get_tails_file(request: web.BaseRequest) -> web.FileResponse: @docs(tags=[TAG_TITLE], summary="Set revocation registry state manually") @match_info_schema(AnonCredsRevRegIdMatchInfoSchema()) @querystring_schema(SetRevRegStateQueryStringSchema()) -@response_schema(RevRegResultSchemaAnoncreds(), 200, description="") +@response_schema(RevRegResultSchemaAnonCreds(), 200, description="") @tenant_authentication async def set_rev_reg_state(request: web.BaseRequest): """Request handler to set a revocation registry state manually. diff --git a/acapy_agent/revocation_anoncreds/tests/test_manager.py b/acapy_agent/revocation_anoncreds/tests/test_manager.py index eeacc02929..05d60f0246 100644 --- a/acapy_agent/revocation_anoncreds/tests/test_manager.py +++ b/acapy_agent/revocation_anoncreds/tests/test_manager.py @@ -8,9 +8,7 @@ V10CredentialExchange, ) from ...protocols.issue_credential.v2_0.models.cred_ex_record import V20CredExRecord -from ...revocation.models.issuer_cred_rev_record import ( - IssuerCredRevRecord, -) +from ...revocation.models.issuer_cred_rev_record import IssuerCredRevRecord from ...tests import mock from ...utils.testing import create_test_profile from .. import manager as test_module @@ -32,7 +30,7 @@ async def asyncSetUp(self): self.profile = await create_test_profile() self.manager = RevocationManager(self.profile) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_revoke_credential_publish(self): CRED_EX_ID = "dummy-cxid" CRED_REV_ID = "1" @@ -112,7 +110,7 @@ async def test_revoke_cred_by_cxid_not_found(self): with self.assertRaises(RevocationManagerError): await self.manager.revoke_credential_by_cred_ex_id(CRED_EX_ID) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_revoke_credential_no_rev_reg_rec(self): CRED_REV_ID = "1" V10CredentialExchange( @@ -134,7 +132,7 @@ async def test_revoke_credential_no_rev_reg_rec(self): with self.assertRaises(RevocationManagerError): await self.manager.revoke_credential(REV_REG_ID, CRED_REV_ID) - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_revoke_credential_pend(self): CRED_REV_ID = "1" mock_issuer_rev_reg_record = mock.MagicMock(mark_pending=mock.AsyncMock()) @@ -170,7 +168,7 @@ async def test_revoke_credential_pend(self): issuer.revoke_credentials.assert_not_awaited() - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_publish_pending_revocations_basic(self): deltas = [ { @@ -218,7 +216,7 @@ async def test_publish_pending_revocations_basic(self): assert result == {REV_REG_ID: ["1", "2"]} mock_issuer_rev_reg_record.clear_pending.assert_called_once() - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_publish_pending_revocations_1_rev_reg_all(self): deltas = [ { @@ -280,7 +278,7 @@ async def test_publish_pending_revocations_1_rev_reg_all(self): mock_issuer_rev_reg_records[0].clear_pending.assert_called_once() mock_issuer_rev_reg_records[1].clear_pending.assert_not_called() - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_publish_pending_revocations_1_rev_reg_some(self): deltas = [ { @@ -342,7 +340,7 @@ async def test_publish_pending_revocations_1_rev_reg_some(self): mock_issuer_rev_reg_records[0].clear_pending.assert_called_once() mock_issuer_rev_reg_records[1].clear_pending.assert_not_called() - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_clear_pending(self): mock_issuer_rev_reg_records = [ mock.MagicMock( @@ -366,7 +364,7 @@ async def test_clear_pending(self): result = await self.manager.clear_pending_revocations() assert result == {} - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_clear_pending_1_rev_reg_all(self): mock_issuer_rev_reg_records = [ mock.MagicMock( @@ -393,7 +391,7 @@ async def test_clear_pending_1_rev_reg_all(self): f"{TEST_DID}:4:{CRED_DEF_ID}:CL_ACCUM:tag2": ["9", "99"], } - @pytest.mark.skip(reason="Anoncreds-break") + @pytest.mark.skip(reason="AnonCreds-break") async def test_clear_pending_1_rev_reg_some(self): mock_issuer_rev_reg_records = [ mock.MagicMock( diff --git a/acapy_agent/revocation_anoncreds/tests/test_routes.py b/acapy_agent/revocation_anoncreds/tests/test_routes.py index 40f2edda3e..fa340f9235 100644 --- a/acapy_agent/revocation_anoncreds/tests/test_routes.py +++ b/acapy_agent/revocation_anoncreds/tests/test_routes.py @@ -38,7 +38,7 @@ async def asyncSetUp(self): async def test_validate_cred_rev_rec_qs_and_revoke_req(self): for req in ( test_module.CredRevRecordQueryStringSchema(), - test_module.RevokeRequestSchemaAnoncreds(), + test_module.RevokeRequestSchemaAnonCreds(), ): req.validate_fields( { diff --git a/acapy_agent/utils/profiles.py b/acapy_agent/utils/profiles.py index f1afec248d..9c9b0f6df9 100644 --- a/acapy_agent/utils/profiles.py +++ b/acapy_agent/utils/profiles.py @@ -5,7 +5,7 @@ from aiohttp import web from ..anoncreds.error_messages import ANONCREDS_PROFILE_REQUIRED_MSG -from ..askar.profile_anon import AskarAnoncredsProfile +from ..askar.profile_anon import AskarAnonCredsProfile from ..core.profile import Profile from ..multitenant.manager import MultitenantManager from ..multitenant.single_wallet_askar_manager import SingleWalletAskarMultitenantManager @@ -15,13 +15,13 @@ def is_anoncreds_profile_raise_web_exception(profile: Profile) -> None: """Raise a web exception when the supplied profile is anoncreds.""" - if isinstance(profile, AskarAnoncredsProfile): + if isinstance(profile, AskarAnonCredsProfile): raise web.HTTPForbidden(reason="Interface not supported for an anoncreds profile") def is_not_anoncreds_profile_raise_web_exception(profile: Profile) -> None: """Raise a web exception when the supplied profile is anoncreds.""" - if not isinstance(profile, AskarAnoncredsProfile): + if not isinstance(profile, AskarAnonCredsProfile): raise web.HTTPForbidden(reason=ANONCREDS_PROFILE_REQUIRED_MSG) diff --git a/acapy_agent/utils/testing.py b/acapy_agent/utils/testing.py index 2ee34cf125..1251043905 100644 --- a/acapy_agent/utils/testing.py +++ b/acapy_agent/utils/testing.py @@ -4,14 +4,14 @@ from uuid import uuid4 from ..askar.profile import AskarProfile -from ..askar.profile_anon import AskarAnoncredsProfile +from ..askar.profile_anon import AskarAnonCredsProfile from ..askar.store import AskarStoreConfig from ..config.injection_context import InjectionContext async def create_test_profile( settings: Optional[dict] = None, context: Optional[InjectionContext] = None -) -> AskarProfile | AskarAnoncredsProfile: +) -> AskarProfile | AskarAnonCredsProfile: """Create a profile for testing.""" if not settings: settings = { @@ -38,7 +38,7 @@ async def create_test_profile( opened = await store_config.open_store(provision=True, in_memory=True) if settings.get("wallet.type") == "askar-anoncreds": - return AskarAnoncredsProfile( + return AskarAnonCredsProfile( opened=opened, context=context, ) diff --git a/acapy_agent/vc/data_integrity/cryptosuites/eddsa_jcs_2022.py b/acapy_agent/vc/data_integrity/cryptosuites/eddsa_jcs_2022.py index b0520aa8be..dd6bcaf460 100644 --- a/acapy_agent/vc/data_integrity/cryptosuites/eddsa_jcs_2022.py +++ b/acapy_agent/vc/data_integrity/cryptosuites/eddsa_jcs_2022.py @@ -1,22 +1,23 @@ """EddsaJcs2022 cryptosuite.""" +from datetime import datetime from hashlib import sha256 + import canonicaljson +from ....core.error import BaseError +from ....core.profile import ProfileSession +from ....utils.multiformats import multibase from ....wallet.base import BaseWallet from ....wallet.keys.manager import ( MultikeyManager, - multikey_to_verkey, key_type_from_multikey, + multikey_to_verkey, ) -from ....utils.multiformats import multibase -from ....core.profile import ProfileSession -from ....core.error import BaseError +from ..errors import PROBLEM_DETAILS from ..models.options import DataIntegrityProofOptions from ..models.proof import DataIntegrityProof -from ..models.verification_response import ProblemDetails, DataIntegrityVerificationResult -from ..errors import PROBLEM_DETAILS -from datetime import datetime +from ..models.verification_response import DataIntegrityVerificationResult, ProblemDetails class CryptosuiteError(BaseError): diff --git a/acapy_agent/vc/data_integrity/manager.py b/acapy_agent/vc/data_integrity/manager.py index 401aafaab2..65ef6d170e 100644 --- a/acapy_agent/vc/data_integrity/manager.py +++ b/acapy_agent/vc/data_integrity/manager.py @@ -1,19 +1,19 @@ """DataIntegrity class.""" -from ...core.profile import ProfileSession +from datetime import datetime + from ...core.error import BaseError +from ...core.profile import ProfileSession from ...resolver.base import DIDNotFound from .cryptosuites import EddsaJcs2022 -from .models.proof import DataIntegrityProof +from .errors import PROBLEM_DETAILS from .models.options import DataIntegrityProofOptions +from .models.proof import DataIntegrityProof from .models.verification_response import ( DataIntegrityVerificationResponse, DataIntegrityVerificationResult, ProblemDetails, ) -from .errors import PROBLEM_DETAILS - -from datetime import datetime CRYPTOSUITES = { "eddsa-jcs-2022": EddsaJcs2022, diff --git a/acapy_agent/vc/data_integrity/models/__init__.py b/acapy_agent/vc/data_integrity/models/__init__.py index c0b38b4a18..f031ab7291 100644 --- a/acapy_agent/vc/data_integrity/models/__init__.py +++ b/acapy_agent/vc/data_integrity/models/__init__.py @@ -1,8 +1,8 @@ -from .proof import DataIntegrityProof, DataIntegrityProofSchema from .options import DataIntegrityProofOptions, DataIntegrityProofOptionsSchema +from .proof import DataIntegrityProof, DataIntegrityProofSchema from .verification_response import ( - DataIntegrityVerificationResponseSchema, DataIntegrityVerificationResponse, + DataIntegrityVerificationResponseSchema, ) __all__ = [ diff --git a/acapy_agent/vc/data_integrity/models/options.py b/acapy_agent/vc/data_integrity/models/options.py index 5d8915add7..2fe39a1377 100644 --- a/acapy_agent/vc/data_integrity/models/options.py +++ b/acapy_agent/vc/data_integrity/models/options.py @@ -5,11 +5,7 @@ from marshmallow import INCLUDE, fields, post_dump from ....messaging.models.base import BaseModel, BaseModelSchema -from ....messaging.valid import ( - RFC3339_DATETIME_EXAMPLE, - UUID4_EXAMPLE, - Uri, -) +from ....messaging.valid import RFC3339_DATETIME_EXAMPLE, UUID4_EXAMPLE, Uri class DataIntegrityProofOptions(BaseModel): diff --git a/acapy_agent/vc/data_integrity/models/proof.py b/acapy_agent/vc/data_integrity/models/proof.py index 6ba869c354..ad17ff5f1b 100644 --- a/acapy_agent/vc/data_integrity/models/proof.py +++ b/acapy_agent/vc/data_integrity/models/proof.py @@ -5,11 +5,7 @@ from marshmallow import INCLUDE, fields, post_dump from ....messaging.models.base import BaseModel, BaseModelSchema -from ....messaging.valid import ( - RFC3339_DATETIME_EXAMPLE, - UUID4_EXAMPLE, - Uri, -) +from ....messaging.valid import RFC3339_DATETIME_EXAMPLE, UUID4_EXAMPLE, Uri class DataIntegrityProof(BaseModel): diff --git a/acapy_agent/vc/data_integrity/models/verification_response.py b/acapy_agent/vc/data_integrity/models/verification_response.py index f69d0b877e..2e16eded09 100644 --- a/acapy_agent/vc/data_integrity/models/verification_response.py +++ b/acapy_agent/vc/data_integrity/models/verification_response.py @@ -1,6 +1,6 @@ """DataIntegrityProof.""" -from typing import Optional, List +from typing import List, Optional from marshmallow import INCLUDE, fields diff --git a/acapy_agent/vc/data_integrity/routes.py b/acapy_agent/vc/data_integrity/routes.py index 55bdf3bdcc..d87da63474 100644 --- a/acapy_agent/vc/data_integrity/routes.py +++ b/acapy_agent/vc/data_integrity/routes.py @@ -6,13 +6,12 @@ from aiohttp_apispec import docs, request_schema, response_schema from marshmallow import fields - from ...admin.decorators.auth import tenant_authentication from ...admin.request_context import AdminRequestContext from ...messaging.models.openapi import OpenAPISchema -from .manager import DataIntegrityManager, DataIntegrityManagerError -from .models import DataIntegrityProofOptionsSchema, DataIntegrityProofOptions from ...wallet.error import WalletError +from .manager import DataIntegrityManager, DataIntegrityManagerError +from .models import DataIntegrityProofOptions, DataIntegrityProofOptionsSchema LOGGER = logging.getLogger(__name__) diff --git a/acapy_agent/vc/ld_proofs/__init__.py b/acapy_agent/vc/ld_proofs/__init__.py index 36c77f84f8..c4a7364c98 100644 --- a/acapy_agent/vc/ld_proofs/__init__.py +++ b/acapy_agent/vc/ld_proofs/__init__.py @@ -12,9 +12,9 @@ from .purposes import _ProofPurpose as ProofPurpose from .suites import _BbsBlsSignature2020 as BbsBlsSignature2020 from .suites import _BbsBlsSignatureProof2020 as BbsBlsSignatureProof2020 +from .suites import _EcdsaSecp256r1Signature2019 as EcdsaSecp256r1Signature2019 from .suites import _Ed25519Signature2018 as Ed25519Signature2018 from .suites import _Ed25519Signature2020 as Ed25519Signature2020 -from .suites import _EcdsaSecp256r1Signature2019 as EcdsaSecp256r1Signature2019 from .suites import _JwsLinkedDataSignature as JwsLinkedDataSignature from .suites import _LinkedDataProof as LinkedDataProof from .suites import _LinkedDataSignature as LinkedDataSignature diff --git a/acapy_agent/vc/ld_proofs/crypto/wallet_key_pair.py b/acapy_agent/vc/ld_proofs/crypto/wallet_key_pair.py index 8e7d280b67..df92a58a99 100644 --- a/acapy_agent/vc/ld_proofs/crypto/wallet_key_pair.py +++ b/acapy_agent/vc/ld_proofs/crypto/wallet_key_pair.py @@ -1,15 +1,16 @@ """Key pair based on base wallet interface.""" from typing import List, Optional, Union + from base58 import b58encode from ....core.profile import Profile +from ....utils.multiformats import multibase, multicodec from ....wallet.base import BaseWallet from ....wallet.key_type import KeyType from ....wallet.util import b58_to_bytes from ..error import LinkedDataProofException from .key_pair import KeyPair -from ....utils.multiformats import multibase, multicodec class WalletKeyPair(KeyPair): diff --git a/acapy_agent/vc/ld_proofs/suites/__init__.py b/acapy_agent/vc/ld_proofs/suites/__init__.py index 71456f6744..9728226d7b 100644 --- a/acapy_agent/vc/ld_proofs/suites/__init__.py +++ b/acapy_agent/vc/ld_proofs/suites/__init__.py @@ -2,11 +2,11 @@ from .bbs_bls_signature_proof_2020 import ( BbsBlsSignatureProof2020 as _BbsBlsSignatureProof2020, ) -from .ed25519_signature_2018 import Ed25519Signature2018 as _Ed25519Signature2018 -from .ed25519_signature_2020 import Ed25519Signature2020 as _Ed25519Signature2020 from .ecdsa_secp256r1_signature_2019 import ( EcdsaSecp256r1Signature2019 as _EcdsaSecp256r1Signature2019, ) +from .ed25519_signature_2018 import Ed25519Signature2018 as _Ed25519Signature2018 +from .ed25519_signature_2020 import Ed25519Signature2020 as _Ed25519Signature2020 from .jws_linked_data_signature import JwsLinkedDataSignature as _JwsLinkedDataSignature from .linked_data_proof import LinkedDataProof as _LinkedDataProof from .linked_data_signature import LinkedDataSignature as _LinkedDataSignature diff --git a/acapy_agent/vc/ld_proofs/tests/test_document_downloader.py b/acapy_agent/vc/ld_proofs/tests/test_document_downloader.py index bd8fc50281..fb04711ff7 100644 --- a/acapy_agent/vc/ld_proofs/tests/test_document_downloader.py +++ b/acapy_agent/vc/ld_proofs/tests/test_document_downloader.py @@ -1,8 +1,6 @@ from unittest.mock import Mock -from acapy_agent.vc.ld_proofs.document_downloader import ( - StaticCacheJsonLdDownloader, -) +from acapy_agent.vc.ld_proofs.document_downloader import StaticCacheJsonLdDownloader def test_load_cache_hit(): diff --git a/acapy_agent/vc/tests/contexts/__init__.py b/acapy_agent/vc/tests/contexts/__init__.py index de43b411e2..64810d4fde 100644 --- a/acapy_agent/vc/tests/contexts/__init__.py +++ b/acapy_agent/vc/tests/contexts/__init__.py @@ -5,8 +5,8 @@ from .did_v1 import DID_V1 from .dif_presentation_submission_v1 import DIF_PRESENTATION_SUBMISSION_V1 from .ed25519_2020_v1 import ED25519_2020_V1 -from .multikey_v1 import MULTIKEY_V1 from .examples_v1 import EXAMPLES_V1 +from .multikey_v1 import MULTIKEY_V1 from .odrl import ODRL from .schema_org import SCHEMA_ORG from .security_v1 import SECURITY_V1 diff --git a/acapy_agent/vc/tests/data/__init__.py b/acapy_agent/vc/tests/data/__init__.py index 38bd5c7e1d..ab241533c4 100644 --- a/acapy_agent/vc/tests/data/__init__.py +++ b/acapy_agent/vc/tests/data/__init__.py @@ -12,9 +12,7 @@ from .bbs_vc_mattr import BBS_VC_MATTR from .bbs_vc_reveal_document_mattr import BBS_VC_REVEAL_DOCUMENT_MATTR from .test_ld_document import TEST_LD_DOCUMENT -from .test_ld_document_bad_partial_proof_bbs import ( - TEST_LD_DOCUMENT_BAD_PARTIAL_PROOF_BBS, -) +from .test_ld_document_bad_partial_proof_bbs import TEST_LD_DOCUMENT_BAD_PARTIAL_PROOF_BBS from .test_ld_document_bad_signed_bbs import TEST_LD_DOCUMENT_BAD_SIGNED_BBS from .test_ld_document_bad_signed_ed25519 import TEST_LD_DOCUMENT_BAD_SIGNED_ED25519 from .test_ld_document_bad_signed_ed25519_2020 import ( diff --git a/acapy_agent/vc/tests/document_loader.py b/acapy_agent/vc/tests/document_loader.py index 04cccd5f83..cf40147992 100644 --- a/acapy_agent/vc/tests/document_loader.py +++ b/acapy_agent/vc/tests/document_loader.py @@ -4,10 +4,10 @@ DID_V1_CONTEXT_URL, SECURITY_CONTEXT_BBS_URL, SECURITY_CONTEXT_ED25519_2020_URL, + SECURITY_CONTEXT_MULTIKEY_URL, SECURITY_CONTEXT_V1_URL, SECURITY_CONTEXT_V2_URL, SECURITY_CONTEXT_V3_URL, - SECURITY_CONTEXT_MULTIKEY_URL, ) from .contexts import ( BBS_V1, @@ -17,8 +17,8 @@ DID_V1, DIF_PRESENTATION_SUBMISSION_V1, ED25519_2020_V1, - MULTIKEY_V1, EXAMPLES_V1, + MULTIKEY_V1, ODRL, SCHEMA_ORG, SECURITY_V1, diff --git a/acapy_agent/vc/vc_ld/models/tests/test_credential.py b/acapy_agent/vc/vc_ld/models/tests/test_credential.py index 4ac3716ce8..d7ef66b335 100644 --- a/acapy_agent/vc/vc_ld/models/tests/test_credential.py +++ b/acapy_agent/vc/vc_ld/models/tests/test_credential.py @@ -3,10 +3,7 @@ from marshmallow.utils import INCLUDE -from ....ld_proofs.constants import ( - CREDENTIALS_CONTEXT_V1_URL, - VERIFIABLE_CREDENTIAL_TYPE, -) +from ....ld_proofs.constants import CREDENTIALS_CONTEXT_V1_URL, VERIFIABLE_CREDENTIAL_TYPE from ...models.credential import VerifiableCredential from ...models.linked_data_proof import LDProof diff --git a/acapy_agent/vc/vc_ld/tests/test_manager.py b/acapy_agent/vc/vc_ld/tests/test_manager.py index cdb327f0c5..381c4265ec 100644 --- a/acapy_agent/vc/vc_ld/tests/test_manager.py +++ b/acapy_agent/vc/vc_ld/tests/test_manager.py @@ -26,15 +26,13 @@ ) from ...ld_proofs.crypto.wallet_key_pair import WalletKeyPair from ...ld_proofs.document_loader import DocumentLoader -from ...ld_proofs.purposes.authentication_proof_purpose import ( - AuthenticationProofPurpose, -) +from ...ld_proofs.purposes.authentication_proof_purpose import AuthenticationProofPurpose from ...ld_proofs.purposes.credential_issuance_purpose import CredentialIssuancePurpose from ...ld_proofs.suites.bbs_bls_signature_2020 import BbsBlsSignature2020 from ...ld_proofs.suites.bbs_bls_signature_proof_2020 import BbsBlsSignatureProof2020 +from ...ld_proofs.suites.ecdsa_secp256r1_signature_2019 import EcdsaSecp256r1Signature2019 from ...ld_proofs.suites.ed25519_signature_2018 import Ed25519Signature2018 from ...ld_proofs.suites.ed25519_signature_2020 import Ed25519Signature2020 -from ...ld_proofs.suites.ecdsa_secp256r1_signature_2019 import EcdsaSecp256r1Signature2019 from ..manager import VcLdpManager, VcLdpManagerError from ..models.credential import VerifiableCredential from ..models.options import LDProofVCOptions diff --git a/acapy_agent/vc/vc_ld/tests/test_vc_ld.py b/acapy_agent/vc/vc_ld/tests/test_vc_ld.py index e2ddb5a8b7..bfcd56ce32 100644 --- a/acapy_agent/vc/vc_ld/tests/test_vc_ld.py +++ b/acapy_agent/vc/vc_ld/tests/test_vc_ld.py @@ -15,14 +15,9 @@ ) from ...ld_proofs.error import LinkedDataProofException from ...tests.document_loader import custom_document_loader -from ...vc_ld import ( - create_presentation, - derive_credential, - sign_presentation, - verify_credential, - verify_presentation, -) +from ...vc_ld import create_presentation, derive_credential from ...vc_ld import issue_vc as issue +from ...vc_ld import sign_presentation, verify_credential, verify_presentation from .test_credential import ( CREDENTIAL_ISSUED, CREDENTIAL_ISSUED_2020, diff --git a/acapy_agent/vc/vc_ld/tests/test_vc_v2.py b/acapy_agent/vc/vc_ld/tests/test_vc_v2.py index b2d6417499..c409c9fd79 100644 --- a/acapy_agent/vc/vc_ld/tests/test_vc_v2.py +++ b/acapy_agent/vc/vc_ld/tests/test_vc_v2.py @@ -5,24 +5,17 @@ from ....utils.testing import create_test_profile from ....wallet.base import BaseWallet from ....wallet.key_type import ED25519 -from ...ld_proofs import ( - Ed25519Signature2020, - WalletKeyPair, -) +from ...ld_proofs import Ed25519Signature2020, WalletKeyPair from ...ld_proofs.error import LinkedDataProofException from ...tests.document_loader import custom_document_loader -from ...vc_ld import ( - sign_presentation, - verify_credential, - verify_presentation, -) from ...vc_ld import issue_vc as issue +from ...vc_ld import sign_presentation, verify_credential, verify_presentation from .test_credential_v2 import ( CREDENTIAL_V2_ISSUED, CREDENTIAL_V2_TEMPLATE, CREDENTIAL_V2_VERIFIED, - PRESENTATION_V2_UNSIGNED, PRESENTATION_V2_SIGNED, + PRESENTATION_V2_UNSIGNED, ) diff --git a/acapy_agent/wallet/anoncreds_upgrade.py b/acapy_agent/wallet/anoncreds_upgrade.py index f0d5c421dc..0636edd917 100644 --- a/acapy_agent/wallet/anoncreds_upgrade.py +++ b/acapy_agent/wallet/anoncreds_upgrade.py @@ -56,7 +56,7 @@ RECORD_TYPE_ACAPY_UPGRADING, STORAGE_TYPE_VALUE_ANONCREDS, ) -from .singletons import IsAnoncredsSingleton, UpgradeInProgressSingleton +from .singletons import IsAnonCredsSingleton, UpgradeInProgressSingleton LOGGER = logging.getLogger(__name__) @@ -603,7 +603,7 @@ async def upgrade_wallet_to_anoncreds_if_requested( try: upgrading_record = await storage.find_record(RECORD_TYPE_ACAPY_UPGRADING, {}) if upgrading_record.value == UPGRADING_RECORD_FINISHED: - IsAnoncredsSingleton().set_wallet(profile.name) + IsAnonCredsSingleton().set_wallet(profile.name) return except StorageNotFoundError: return @@ -639,7 +639,7 @@ async def finish_upgrade(profile: Profile): ) ) await finish_upgrading_record(profile) - IsAnoncredsSingleton().set_wallet(profile.name) + IsAnonCredsSingleton().set_wallet(profile.name) UpgradeInProgressSingleton().remove_wallet(profile.name) @@ -696,7 +696,7 @@ async def check_upgrade_completion_loop(profile: Profile, is_subwallet=False): RECORD_TYPE_ACAPY_UPGRADING, tag_query={} ) if upgrading_record.value == UPGRADING_RECORD_FINISHED: - IsAnoncredsSingleton().set_wallet(profile.name) + IsAnonCredsSingleton().set_wallet(profile.name) UpgradeInProgressSingleton().remove_wallet(profile.name) if is_subwallet: await upgrade_subwallet(profile) diff --git a/acapy_agent/wallet/default_verification_key_strategy.py b/acapy_agent/wallet/default_verification_key_strategy.py index be9eb0de36..a07dedfe4c 100644 --- a/acapy_agent/wallet/default_verification_key_strategy.py +++ b/acapy_agent/wallet/default_verification_key_strategy.py @@ -1,7 +1,7 @@ """Utilities for specifying which verification method is in use for a given DID.""" -from abc import ABC, abstractmethod import logging +from abc import ABC, abstractmethod from typing import Literal, Optional from pydid import DIDDocument diff --git a/acapy_agent/wallet/keys/manager.py b/acapy_agent/wallet/keys/manager.py index a7ca3595a6..a2bab470b8 100644 --- a/acapy_agent/wallet/keys/manager.py +++ b/acapy_agent/wallet/keys/manager.py @@ -1,12 +1,12 @@ """Multikey class.""" from ...core.profile import ProfileSession +from ...resolver.did_resolver import DIDResolver +from ...utils.multiformats import multibase +from ...wallet.error import WalletNotFoundError from ..base import BaseWallet from ..key_type import BLS12381G2, ED25519, P256, KeyType from ..util import b58_to_bytes, bytes_to_b58 -from ...utils.multiformats import multibase -from ...wallet.error import WalletNotFoundError -from ...resolver.did_resolver import DIDResolver DEFAULT_ALG = "ed25519" ALG_MAPPINGS = { diff --git a/acapy_agent/wallet/keys/routes.py b/acapy_agent/wallet/keys/routes.py index 46647fc9b9..b2e4da7dbf 100644 --- a/acapy_agent/wallet/keys/routes.py +++ b/acapy_agent/wallet/keys/routes.py @@ -9,8 +9,8 @@ from ...admin.decorators.auth import tenant_authentication from ...admin.request_context import AdminRequestContext from ...messaging.models.openapi import OpenAPISchema -from .manager import MultikeyManager, MultikeyManagerError, DEFAULT_ALG from ...wallet.error import WalletDuplicateError, WalletNotFoundError +from .manager import DEFAULT_ALG, MultikeyManager, MultikeyManagerError LOGGER = logging.getLogger(__name__) diff --git a/acapy_agent/wallet/routes.py b/acapy_agent/wallet/routes.py index 9da8e70ba2..cd68be1d14 100644 --- a/acapy_agent/wallet/routes.py +++ b/acapy_agent/wallet/routes.py @@ -1497,8 +1497,8 @@ def post_process_routes(app: web.Application): ) app._state["swagger_dict"]["tags"].append( { - "name": "anoncreds - wallet upgrade", - "description": "Anoncreds wallet upgrade", + "name": "AnonCreds - Wallet Upgrade", + "description": "AnonCreds wallet upgrade", "externalDocs": { "description": "Specification", "url": "https://hyperledger.github.io/anoncreds-spec", diff --git a/acapy_agent/wallet/singletons.py b/acapy_agent/wallet/singletons.py index 9a7a91d057..61fb0d1e05 100644 --- a/acapy_agent/wallet/singletons.py +++ b/acapy_agent/wallet/singletons.py @@ -1,7 +1,7 @@ """Module that contains singleton classes for wallet operations.""" -class IsAnoncredsSingleton: +class IsAnonCredsSingleton: """Singleton class used as cache for anoncreds wallet-type queries.""" instance = None diff --git a/acapy_agent/wallet/tests/test_anoncreds_upgrade.py b/acapy_agent/wallet/tests/test_anoncreds_upgrade.py index 9e6c0f04ad..5810d1477d 100644 --- a/acapy_agent/wallet/tests/test_anoncreds_upgrade.py +++ b/acapy_agent/wallet/tests/test_anoncreds_upgrade.py @@ -26,7 +26,7 @@ from .. import anoncreds_upgrade -class TestAnoncredsUpgrade(IsolatedAsyncioTestCase): +class TestAnonCredsUpgrade(IsolatedAsyncioTestCase): async def asyncSetUp(self) -> None: self.profile = await create_test_profile(settings={"wallet.type": "askar"}) self.profile.context.injector.bind_instance( diff --git a/acapy_agent/wallet/tests/test_default_verification_key_strategy.py b/acapy_agent/wallet/tests/test_default_verification_key_strategy.py index 64649e72a0..bd96e5d19e 100644 --- a/acapy_agent/wallet/tests/test_default_verification_key_strategy.py +++ b/acapy_agent/wallet/tests/test_default_verification_key_strategy.py @@ -1,14 +1,13 @@ from unittest import IsolatedAsyncioTestCase + import pytest from acapy_agent.resolver.did_resolver import DIDResolver -from ...resolver.tests.test_did_resolver import MockResolver from ...did.did_key import DIDKey +from ...resolver.tests.test_did_resolver import MockResolver from ...utils.testing import create_test_profile -from ...wallet.default_verification_key_strategy import ( - DefaultVerificationKeyStrategy, -) +from ...wallet.default_verification_key_strategy import DefaultVerificationKeyStrategy TEST_DID_SOV = "did:sov:LjgpST2rjsoxYegQDRm7EL" TEST_DID_KEY = "did:key:z6Mkgg342Ycpuk263R9d8Aq6MUaxPn1DDeHyGo38EefXmgDL" diff --git a/conftest.py b/conftest.py index 51c760b702..172d801e21 100644 --- a/conftest.py +++ b/conftest.py @@ -33,10 +33,10 @@ def stub_anoncreds() -> Stub: _ = generate_nonce() return Stub(None) except ImportError: - print("Skipping Anoncreds-specific tests: anoncreds module not installed.") + print("Skipping AnonCreds-specific tests: anoncreds module not installed.") except OSError: print( - "Skipping Anoncreds-specific tests: anoncreds shared library" + "Skipping AnonCreds-specific tests: anoncreds shared library" "could not be loaded." ) @@ -192,7 +192,7 @@ def pytest_runtest_setup(item: pytest.Item): global STUBS if tuple(item.iter_markers(name="anoncreds")) and not STUBS["anoncreds"].found: - pytest.skip("test requires Anoncreds support") + pytest.skip("test requires AnonCreds support") if tuple(item.iter_markers(name="askar")) and not STUBS["askar"].found: pytest.skip("test requires Askar support") diff --git a/demo/features/revocation-api.feature b/demo/features/revocation-api.feature index ca6daf4b03..dc66cdbd69 100644 --- a/demo/features/revocation-api.feature +++ b/demo/features/revocation-api.feature @@ -44,7 +44,7 @@ Feature: ACA-Py Revocation API | Acme | --revocation --public-did --multitenant | --wallet-type askar-anoncreds | driverslicense_v2 | Data_DL_MaxValues | DL_age_over_19_v2 | | Acme | --revocation --public-did --multitenant --wallet-type askar-anoncreds | --wallet-type askar-anoncreds | driverslicense_v2 | Data_DL_MaxValues | DL_age_over_19_v2 | - @Revoc-api.x @PR-Anoncreds-break + @Revoc-api.x @PR-AnonCreds-break Scenario Outline: Without endorser: issue, revoke credentials, manually create revocation registries Given we have "3" agents | name | role | capabilities | diff --git a/demo/features/upgrade.feature b/demo/features/upgrade.feature index 557dd75646..cb5e816984 100644 --- a/demo/features/upgrade.feature +++ b/demo/features/upgrade.feature @@ -1,4 +1,4 @@ -Feature: ACA-Py Anoncreds Upgrade +Feature: ACA-Py AnonCreds Upgrade @PR @Release Scenario Outline: Using revocation api, issue, revoke credentials and publish diff --git a/demo/runners/faber.py b/demo/runners/faber.py index 41948177f9..855bd5523e 100644 --- a/demo/runners/faber.py +++ b/demo/runners/faber.py @@ -522,7 +522,7 @@ async def main(args): if option is not None: option = option.strip() - # Anoncreds has different endpoints for revocation + # AnonCreds has different endpoints for revocation is_anoncreds = False if ( faber_agent.agent.__dict__["wallet_type"] == "askar-anoncreds" diff --git a/docs/design/AnoncredsW3CCompatibility.md b/docs/design/AnonCredsW3CCompatibility.md similarity index 100% rename from docs/design/AnoncredsW3CCompatibility.md rename to docs/design/AnonCredsW3CCompatibility.md diff --git a/docs/design/UpgradeViaApi.md b/docs/design/UpgradeViaApi.md index f9a472e962..797157dc8f 100644 --- a/docs/design/UpgradeViaApi.md +++ b/docs/design/UpgradeViaApi.md @@ -12,11 +12,11 @@ The diagram below describes the sequence of events for the anoncreds upgrade pro sequenceDiagram participant A1 as Agent 1 participant M1 as Middleware - participant IAS1 as IsAnoncredsSingleton Set + participant IAS1 as IsAnonCredsSingleton Set participant UIPS1 as UpgradeInProgressSingleton Set participant W as Wallet (DB) participant UIPS2 as UpgradeInProgressSingleton Set - participant IAS2 as IsAnoncredsSingleton Set + participant IAS2 as IsAnonCredsSingleton Set participant M2 as Middleware participant A2 as Agent 2 diff --git a/docs/features/AnoncredsProofValidation.md b/docs/features/AnonCredsProofValidation.md similarity index 99% rename from docs/features/AnoncredsProofValidation.md rename to docs/features/AnonCredsProofValidation.md index 354d999496..5abff5af66 100644 --- a/docs/features/AnoncredsProofValidation.md +++ b/docs/features/AnonCredsProofValidation.md @@ -74,7 +74,7 @@ A summary of the possible errors includes: - Self-attested attribute provided for a requested attribute with restrictions - Encoded value doesn't match raw value -## Anoncreds Verification Exceptions +## AnonCreds Verification Exceptions Typically, when you call the anoncreds `verifier_verify_proof()` method, it will return a `True` or `False` based on whether the presentation cryptographically verifies. However, in the case where anoncreds throws an exception, the exception text will be included in a verification message as follows: diff --git a/mkdocs.yml b/mkdocs.yml index 570180b6a9..0a6ea6126c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -100,7 +100,7 @@ nav: - Using W3C JSON-LD Signed Credentials: features/JsonLdCredentials.md - Issuing and Presenting W3C Data Integrity VCs: features/W3cCredentials.md - Using SD-JWTs: features/SelectiveDisclosureJWTs.md - - AnonCreds Presentation Validation: features/AnoncredsProofValidation.md + - AnonCreds Presentation Validation: features/AnonCredsProofValidation.md - Multiple Credential Types: features/Multicredentials.md - Code Generation with the Open API: features/UsingOpenAPI.md - ACA-Py as a DIDComm Mediator: features/Mediation.md @@ -138,7 +138,7 @@ nav: - Upgrading ACA-Py: deploying/UpgradingACA-Py.md - Enabling BBS Signatures support: deploying/BBSSignatures.md - Indy SDK to Askar Migration: deploying/IndySDKtoAskarMigration.md - - Controller Migration to use AnonCreds Rust: deploying/AnoncredsControllerMigration.md + - Controller Migration to use AnonCreds Rust: deploying/AnonCredsControllerMigration.md - The Use of Poetry in ACA-Py: deploying/Poetry.md - ACA-Py Container Images: deploying/ContainerImagesAndGithubActions.md - Databases: deploying/Databases.md diff --git a/open-api/openapi.json b/open-api/openapi.json index 6febd23147..c33c50f766 100644 --- a/open-api/openapi.json +++ b/open-api/openapi.json @@ -11,36 +11,36 @@ "AuthorizationHeader" : [ ] } ], "tags" : [ { - "description" : "Menu interaction over connection", - "name" : "action-menu" - }, { - "description" : "Anoncreds credential definition management", + "description" : "AnonCreds credential definition management", "externalDocs" : { "description" : "Specification", "url" : "https://hyperledger.github.io/anoncreds-spec" }, - "name" : "anoncreds - credential definitions" + "name" : "AnonCreds - Credential Definitions" }, { "description" : "Revocation registry management", "externalDocs" : { "description" : "Overview", "url" : "https://github.com/hyperledger/indy-hipe/tree/master/text/0011-cred-revocation" }, - "name" : "anoncreds - revocation" + "name" : "AnonCreds - Revocation" }, { - "description" : "Anoncreds schema management", + "description" : "AnonCreds schema management", "externalDocs" : { "description" : "Specification", "url" : "https://hyperledger.github.io/anoncreds-spec" }, - "name" : "anoncreds - schemas" + "name" : "AnonCreds - Schemas" }, { - "description" : "Anoncreds wallet upgrade", + "description" : "AnonCreds wallet upgrade", "externalDocs" : { "description" : "Specification", "url" : "https://hyperledger.github.io/anoncreds-spec" }, - "name" : "anoncreds - wallet upgrade" + "name" : "AnonCreds - Wallet Upgrade" + }, { + "description" : "Menu interaction over connection", + "name" : "action-menu" }, { "description" : "Simple messaging", "externalDocs" : { @@ -489,7 +489,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/AnoncredsRevocationModuleResponse" + "$ref" : "#/components/schemas/AnonCredsRevocationModuleResponse" } } }, @@ -517,7 +517,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/AnoncredsRevocationModuleResponse" + "$ref" : "#/components/schemas/AnonCredsRevocationModuleResponse" } } }, @@ -563,7 +563,7 @@ "content" : { "*/*" : { "schema" : { - "$ref" : "#/components/schemas/RevRegCreateRequestSchemaAnoncreds" + "$ref" : "#/components/schemas/RevRegCreateRequestSchemaAnonCreds" } } }, @@ -603,7 +603,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/RevRegResultSchemaAnoncreds" + "$ref" : "#/components/schemas/RevRegResultSchemaAnonCreds" } } }, @@ -611,7 +611,7 @@ } }, "summary" : "Get current active revocation registry by credential definition id", - "tags" : [ "anoncreds - revocation" ] + "tags" : [ "AnonCreds - Revocation" ] } }, "/anoncreds/revocation/active-registry/{cred_def_id}/rotate" : { @@ -631,7 +631,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/RevRegsCreatedSchemaAnoncreds" + "$ref" : "#/components/schemas/RevRegsCreatedSchemaAnonCreds" } } }, @@ -639,7 +639,7 @@ } }, "summary" : "Rotate revocation registry", - "tags" : [ "anoncreds - revocation" ] + "tags" : [ "AnonCreds - Revocation" ] } }, "/anoncreds/revocation/credential-record" : { @@ -674,7 +674,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/CredRevRecordResultSchemaAnoncreds" + "$ref" : "#/components/schemas/CredRevRecordResultSchemaAnonCreds" } } }, @@ -682,7 +682,7 @@ } }, "summary" : "Get credential revocation status", - "tags" : [ "anoncreds - revocation" ] + "tags" : [ "AnonCreds - Revocation" ] } }, "/anoncreds/revocation/publish-revocations" : { @@ -691,7 +691,7 @@ "content" : { "*/*" : { "schema" : { - "$ref" : "#/components/schemas/PublishRevocationsSchemaAnoncreds" + "$ref" : "#/components/schemas/PublishRevocationsSchemaAnonCreds" } } }, @@ -702,7 +702,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/PublishRevocationsResultSchemaAnoncreds" + "$ref" : "#/components/schemas/PublishRevocationsResultSchemaAnonCreds" } } }, @@ -710,7 +710,7 @@ } }, "summary" : "Publish pending revocations to ledger", - "tags" : [ "anoncreds - revocation" ], + "tags" : [ "AnonCreds - Revocation" ], "x-codegen-request-body-name" : "body" } }, @@ -738,7 +738,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/RevRegsCreatedSchemaAnoncreds" + "$ref" : "#/components/schemas/RevRegsCreatedSchemaAnonCreds" } } }, @@ -746,7 +746,7 @@ } }, "summary" : "Search for matching revocation registries that current agent created", - "tags" : [ "anoncreds - revocation" ] + "tags" : [ "AnonCreds - Revocation" ] } }, "/anoncreds/revocation/registry/{rev_reg_id}" : { @@ -766,7 +766,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/RevRegResultSchemaAnoncreds" + "$ref" : "#/components/schemas/RevRegResultSchemaAnonCreds" } } }, @@ -774,7 +774,7 @@ } }, "summary" : "Get revocation registry by revocation registry id", - "tags" : [ "anoncreds - revocation" ] + "tags" : [ "AnonCreds - Revocation" ] } }, "/anoncreds/revocation/registry/{rev_reg_id}/fix-revocation-entry-state" : { @@ -802,7 +802,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/RevRegWalletUpdatedResultSchemaAnoncreds" + "$ref" : "#/components/schemas/RevRegWalletUpdatedResultSchemaAnonCreds" } } }, @@ -810,7 +810,7 @@ } }, "summary" : "Fix revocation state in wallet and return number of updated entries", - "tags" : [ "anoncreds - revocation" ] + "tags" : [ "AnonCreds - Revocation" ] } }, "/anoncreds/revocation/registry/{rev_reg_id}/issued" : { @@ -830,7 +830,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/RevRegIssuedResultSchemaAnoncreds" + "$ref" : "#/components/schemas/RevRegIssuedResultSchemaAnonCreds" } } }, @@ -838,7 +838,7 @@ } }, "summary" : "Get number of credentials issued against revocation registry", - "tags" : [ "anoncreds - revocation" ] + "tags" : [ "AnonCreds - Revocation" ] } }, "/anoncreds/revocation/registry/{rev_reg_id}/issued/details" : { @@ -858,7 +858,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/CredRevRecordDetailsResultSchemaAnoncreds" + "$ref" : "#/components/schemas/CredRevRecordDetailsResultSchemaAnonCreds" } } }, @@ -866,7 +866,7 @@ } }, "summary" : "Get details of credentials issued against revocation registry", - "tags" : [ "anoncreds - revocation" ] + "tags" : [ "AnonCreds - Revocation" ] } }, "/anoncreds/revocation/registry/{rev_reg_id}/issued/indy_recs" : { @@ -886,7 +886,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/CredRevIndyRecordsResultSchemaAnoncreds" + "$ref" : "#/components/schemas/CredRevIndyRecordsResultSchemaAnonCreds" } } }, @@ -894,7 +894,7 @@ } }, "summary" : "Get details of revoked credentials from ledger", - "tags" : [ "anoncreds - revocation" ] + "tags" : [ "AnonCreds - Revocation" ] } }, "/anoncreds/revocation/registry/{rev_reg_id}/set-state" : { @@ -923,7 +923,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/RevRegResultSchemaAnoncreds" + "$ref" : "#/components/schemas/RevRegResultSchemaAnonCreds" } } }, @@ -931,7 +931,7 @@ } }, "summary" : "Set revocation registry state manually", - "tags" : [ "anoncreds - revocation" ] + "tags" : [ "AnonCreds - Revocation" ] } }, "/anoncreds/revocation/registry/{rev_reg_id}/tails-file" : { @@ -951,7 +951,7 @@ "content" : { "application/octet-stream" : { "schema" : { - "$ref" : "#/components/schemas/AnoncredsRevocationModuleResponse" + "$ref" : "#/components/schemas/AnonCredsRevocationModuleResponse" } } }, @@ -959,7 +959,7 @@ } }, "summary" : "Download tails file", - "tags" : [ "anoncreds - revocation" ] + "tags" : [ "AnonCreds - Revocation" ] } }, "/anoncreds/revocation/revoke" : { @@ -968,7 +968,7 @@ "content" : { "*/*" : { "schema" : { - "$ref" : "#/components/schemas/RevokeRequestSchemaAnoncreds" + "$ref" : "#/components/schemas/RevokeRequestSchemaAnonCreds" } } }, @@ -979,7 +979,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/AnoncredsRevocationModuleResponse" + "$ref" : "#/components/schemas/AnonCredsRevocationModuleResponse" } } }, @@ -987,7 +987,7 @@ } }, "summary" : "Revoke an issued credential", - "tags" : [ "anoncreds - revocation" ], + "tags" : [ "AnonCreds - Revocation" ], "x-codegen-request-body-name" : "body" } }, @@ -4565,6 +4565,34 @@ "x-codegen-request-body-name" : "body" } }, + "/out-of-band/invitations" : { + "get" : { + "parameters" : [ { + "description" : "The Out of Band id to fetch", + "in" : "query", + "name" : "oob_id", + "required" : true, + "schema" : { + "pattern" : "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", + "type" : "string" + } + } ], + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InvitationRecordResponse" + } + } + }, + "description" : "" + } + }, + "summary" : "Fetch an existing Out-of-Band invitation.", + "tags" : [ "out-of-band" ] + } + }, "/out-of-band/invitations/{invi_msg_id}" : { "delete" : { "parameters" : [ { @@ -7751,48 +7779,18 @@ }, "type" : "object" }, - "AnonCredsSchema" : { - "properties" : { - "attrNames" : { - "description" : "Schema attribute names", - "items" : { - "description" : "Attribute name", - "example" : "score", - "type" : "string" - }, - "type" : "array" - }, - "issuerId" : { - "description" : "Issuer Identifier of the credential definition or schema", - "example" : "did:(method):WgWxqztrNooG92RXvxSTWv", - "type" : "string" - }, - "name" : { - "description" : "Schema name", - "example" : "Example schema", - "type" : "string" - }, - "version" : { - "description" : "Schema version", - "example" : "1.0", - "type" : "string" - } - }, - "required" : [ "attrNames", "issuerId", "name", "version" ], - "type" : "object" - }, - "AnoncredsPresSpec" : { + "AnonCredsPresSpec" : { "properties" : { "requested_attributes" : { "additionalProperties" : { - "$ref" : "#/components/schemas/AnoncredsRequestedCredsRequestedAttr" + "$ref" : "#/components/schemas/AnonCredsRequestedCredsRequestedAttr" }, "description" : "Nested object mapping proof request attribute referents to requested-attribute specifiers", "type" : "object" }, "requested_predicates" : { "additionalProperties" : { - "$ref" : "#/components/schemas/AnoncredsRequestedCredsRequestedPred" + "$ref" : "#/components/schemas/AnonCredsRequestedCredsRequestedPred" }, "description" : "Nested object mapping proof request predicate referents to requested-predicate specifiers", "type" : "object" @@ -7815,7 +7813,7 @@ "required" : [ "requested_attributes", "requested_predicates", "self_attested_attributes" ], "type" : "object" }, - "AnoncredsPresentationReqAttrSpec" : { + "AnonCredsPresentationReqAttrSpec" : { "properties" : { "name" : { "description" : "Attribute name", @@ -7831,7 +7829,7 @@ "type" : "array" }, "non_revoked" : { - "$ref" : "#/components/schemas/AnoncredsPresentationReqAttrSpecNonRevoked" + "$ref" : "#/components/schemas/AnonCredsPresentationReqAttrSpecNonRevoked" }, "restrictions" : { "description" : "If present, credential must satisfy one of given restrictions: specify schema_id, schema_issuer_did, schema_name, schema_version, issuer_did, cred_def_id, and/or attr::::value where represents a credential attribute name", @@ -7847,7 +7845,7 @@ }, "type" : "object" }, - "AnoncredsPresentationReqAttrSpecNonRevoked" : { + "AnonCredsPresentationReqAttrSpecNonRevoked" : { "properties" : { "from" : { "description" : "Earliest time of interest in non-revocation interval", @@ -7866,7 +7864,7 @@ }, "type" : "object" }, - "AnoncredsPresentationReqPredSpec" : { + "AnonCredsPresentationReqPredSpec" : { "properties" : { "name" : { "description" : "Attribute name", @@ -7874,7 +7872,7 @@ "type" : "string" }, "non_revoked" : { - "$ref" : "#/components/schemas/AnoncredsPresentationReqPredSpecNonRevoked" + "$ref" : "#/components/schemas/AnonCredsPresentationReqPredSpecNonRevoked" }, "p_type" : { "description" : "Predicate type ('<', '<=', '>=', or '>')", @@ -7901,7 +7899,7 @@ "required" : [ "name", "p_type", "p_value" ], "type" : "object" }, - "AnoncredsPresentationReqPredSpecNonRevoked" : { + "AnonCredsPresentationReqPredSpecNonRevoked" : { "properties" : { "from" : { "description" : "Earliest time of interest in non-revocation interval", @@ -7920,7 +7918,7 @@ }, "type" : "object" }, - "AnoncredsPresentationRequest" : { + "AnonCredsPresentationRequest" : { "properties" : { "name" : { "description" : "Proof request name", @@ -7928,7 +7926,7 @@ "type" : "string" }, "non_revoked" : { - "$ref" : "#/components/schemas/AnoncredsPresentationRequestNonRevoked" + "$ref" : "#/components/schemas/AnonCredsPresentationRequestNonRevoked" }, "nonce" : { "description" : "Nonce", @@ -7938,14 +7936,14 @@ }, "requested_attributes" : { "additionalProperties" : { - "$ref" : "#/components/schemas/AnoncredsPresentationReqAttrSpec" + "$ref" : "#/components/schemas/AnonCredsPresentationReqAttrSpec" }, "description" : "Requested attribute specifications of proof request", "type" : "object" }, "requested_predicates" : { "additionalProperties" : { - "$ref" : "#/components/schemas/AnoncredsPresentationReqPredSpec" + "$ref" : "#/components/schemas/AnonCredsPresentationReqPredSpec" }, "description" : "Requested predicate specifications of proof request", "type" : "object" @@ -7960,7 +7958,7 @@ "required" : [ "requested_attributes", "requested_predicates" ], "type" : "object" }, - "AnoncredsPresentationRequestNonRevoked" : { + "AnonCredsPresentationRequestNonRevoked" : { "properties" : { "from" : { "description" : "Earliest time of interest in non-revocation interval", @@ -7979,7 +7977,7 @@ }, "type" : "object" }, - "AnoncredsRequestedCredsRequestedAttr" : { + "AnonCredsRequestedCredsRequestedAttr" : { "properties" : { "cred_id" : { "description" : "Wallet credential identifier (typically but not necessarily a UUID)", @@ -7994,7 +7992,7 @@ "required" : [ "cred_id" ], "type" : "object" }, - "AnoncredsRequestedCredsRequestedPred" : { + "AnonCredsRequestedCredsRequestedPred" : { "properties" : { "cred_id" : { "description" : "Wallet credential identifier (typically but not necessarily a UUID)", @@ -8012,7 +8010,37 @@ "required" : [ "cred_id" ], "type" : "object" }, - "AnoncredsRevocationModuleResponse" : { + "AnonCredsRevocationModuleResponse" : { + "type" : "object" + }, + "AnonCredsSchema" : { + "properties" : { + "attrNames" : { + "description" : "Schema attribute names", + "items" : { + "description" : "Attribute name", + "example" : "score", + "type" : "string" + }, + "type" : "array" + }, + "issuerId" : { + "description" : "Issuer Identifier of the credential definition or schema", + "example" : "did:(method):WgWxqztrNooG92RXvxSTWv", + "type" : "string" + }, + "name" : { + "description" : "Schema name", + "example" : "Example schema", + "type" : "string" + }, + "version" : { + "description" : "Schema version", + "example" : "1.0", + "type" : "string" + } + }, + "required" : [ "attrNames", "issuerId", "name", "version" ], "type" : "object" }, "AttachDecorator" : { @@ -8783,7 +8811,7 @@ "type" : "string" }, "value" : { - "$ref" : "#/components/schemas/CredDefValueSchemaAnoncreds" + "$ref" : "#/components/schemas/CredDefValueSchemaAnonCreds" } }, "type" : "object" @@ -8915,7 +8943,7 @@ }, "type" : "object" }, - "CredDefValuePrimarySchemaAnoncreds" : { + "CredDefValuePrimarySchemaAnonCreds" : { "properties" : { "n" : { "example" : "0", @@ -8995,7 +9023,7 @@ }, "type" : "object" }, - "CredDefValueRevocationSchemaAnoncreds" : { + "CredDefValueRevocationSchemaAnonCreds" : { "properties" : { "g" : { "example" : "1 1F14F&ECB578F 2 095E45DDF417D", @@ -9044,18 +9072,18 @@ }, "type" : "object" }, - "CredDefValueSchemaAnoncreds" : { + "CredDefValueSchemaAnonCreds" : { "properties" : { "primary" : { "allOf" : [ { - "$ref" : "#/components/schemas/CredDefValuePrimarySchemaAnoncreds" + "$ref" : "#/components/schemas/CredDefValuePrimarySchemaAnonCreds" } ], "description" : "Primary value for credential definition", "type" : "object" }, "revocation" : { "allOf" : [ { - "$ref" : "#/components/schemas/CredDefValueRevocationSchemaAnoncreds" + "$ref" : "#/components/schemas/CredDefValueRevocationSchemaAnonCreds" } ], "description" : "Revocation value for credential definition", "type" : "object" @@ -9086,7 +9114,7 @@ }, "type" : "object" }, - "CredRevIndyRecordsResultSchemaAnoncreds" : { + "CredRevIndyRecordsResultSchemaAnonCreds" : { "properties" : { "rev_reg_delta" : { "additionalProperties" : { @@ -9109,11 +9137,11 @@ }, "type" : "object" }, - "CredRevRecordDetailsResultSchemaAnoncreds" : { + "CredRevRecordDetailsResultSchemaAnonCreds" : { "properties" : { "results" : { "items" : { - "$ref" : "#/components/schemas/IssuerCredRevRecordSchemaAnoncreds" + "$ref" : "#/components/schemas/IssuerCredRevRecordSchemaAnonCreds" }, "type" : "array" } @@ -9128,10 +9156,10 @@ }, "type" : "object" }, - "CredRevRecordResultSchemaAnoncreds" : { + "CredRevRecordResultSchemaAnonCreds" : { "properties" : { "result" : { - "$ref" : "#/components/schemas/IssuerCredRevRecordSchemaAnoncreds" + "$ref" : "#/components/schemas/IssuerCredRevRecordSchemaAnonCreds" } }, "type" : "object" @@ -11670,7 +11698,7 @@ }, "type" : "object" }, - "IssuerCredRevRecordSchemaAnoncreds" : { + "IssuerCredRevRecordSchemaAnonCreds" : { "properties" : { "created_at" : { "description" : "Time of record creation", @@ -12897,7 +12925,7 @@ }, "type" : "object" }, - "PublishRevocationsResultSchemaAnoncreds" : { + "PublishRevocationsResultSchemaAnonCreds" : { "properties" : { "rrid2crid" : { "additionalProperties" : { @@ -12915,7 +12943,7 @@ }, "type" : "object" }, - "PublishRevocationsSchemaAnoncreds" : { + "PublishRevocationsSchemaAnonCreds" : { "properties" : { "options" : { "$ref" : "#/components/schemas/PublishRevocationsOptions" @@ -13175,7 +13203,7 @@ }, "type" : "object" }, - "RevRegCreateRequestSchemaAnoncreds" : { + "RevRegCreateRequestSchemaAnonCreds" : { "properties" : { "options" : { "$ref" : "#/components/schemas/RevRegDefOptions" @@ -13306,7 +13334,7 @@ }, "type" : "object" }, - "RevRegIssuedResultSchemaAnoncreds" : { + "RevRegIssuedResultSchemaAnonCreds" : { "properties" : { "result" : { "description" : "Number of credentials issued against revocation registry", @@ -13325,7 +13353,7 @@ }, "type" : "object" }, - "RevRegResultSchemaAnoncreds" : { + "RevRegResultSchemaAnonCreds" : { "properties" : { "result" : { "$ref" : "#/components/schemas/IssuerRevRegRecord" @@ -13371,7 +13399,7 @@ }, "type" : "object" }, - "RevRegWalletUpdatedResultSchemaAnoncreds" : { + "RevRegWalletUpdatedResultSchemaAnonCreds" : { "properties" : { "accum_calculated" : { "additionalProperties" : { @@ -13411,7 +13439,7 @@ }, "type" : "object" }, - "RevRegsCreatedSchemaAnoncreds" : { + "RevRegsCreatedSchemaAnonCreds" : { "properties" : { "rev_reg_ids" : { "items" : { @@ -13478,7 +13506,7 @@ }, "type" : "object" }, - "RevokeRequestSchemaAnoncreds" : { + "RevokeRequestSchemaAnonCreds" : { "properties" : { "comment" : { "description" : "Optional comment to include in revocation notification", @@ -15666,7 +15694,7 @@ "properties" : { "anoncreds" : { "allOf" : [ { - "$ref" : "#/components/schemas/V20CredFilterAnoncreds" + "$ref" : "#/components/schemas/V20CredFilterAnonCreds" } ], "description" : "Credential filter for anoncreds", "type" : "object" @@ -15695,7 +15723,7 @@ }, "type" : "object" }, - "V20CredFilterAnoncreds" : { + "V20CredFilterAnonCreds" : { "properties" : { "cred_def_id" : { "description" : "Credential definition identifier", @@ -16571,7 +16599,7 @@ "properties" : { "anoncreds" : { "allOf" : [ { - "$ref" : "#/components/schemas/AnoncredsPresentationRequest" + "$ref" : "#/components/schemas/AnonCredsPresentationRequest" } ], "description" : "Presentation proposal for anoncreds", "type" : "object" @@ -16667,7 +16695,7 @@ "properties" : { "anoncreds" : { "allOf" : [ { - "$ref" : "#/components/schemas/AnoncredsPresentationRequest" + "$ref" : "#/components/schemas/AnonCredsPresentationRequest" } ], "description" : "Presentation proposal for anoncreds", "type" : "object" @@ -16725,7 +16753,7 @@ "properties" : { "anoncreds" : { "allOf" : [ { - "$ref" : "#/components/schemas/AnoncredsPresSpec" + "$ref" : "#/components/schemas/AnonCredsPresSpec" } ], "description" : "Presentation specification for anoncreds", "type" : "object" diff --git a/open-api/swagger.json b/open-api/swagger.json index fce01ff1c2..f6eabbc786 100644 --- a/open-api/swagger.json +++ b/open-api/swagger.json @@ -5,36 +5,36 @@ "title" : "Aries Cloud Agent" }, "tags" : [ { - "name" : "action-menu", - "description" : "Menu interaction over connection" - }, { - "name" : "anoncreds - credential definitions", - "description" : "Anoncreds credential definition management", + "name" : "AnonCreds - Credential Definitions", + "description" : "AnonCreds credential definition management", "externalDocs" : { "description" : "Specification", "url" : "https://hyperledger.github.io/anoncreds-spec" } }, { - "name" : "anoncreds - revocation", + "name" : "AnonCreds - Revocation", "description" : "Revocation registry management", "externalDocs" : { "description" : "Overview", "url" : "https://github.com/hyperledger/indy-hipe/tree/master/text/0011-cred-revocation" } }, { - "name" : "anoncreds - schemas", - "description" : "Anoncreds schema management", + "name" : "AnonCreds - Schemas", + "description" : "AnonCreds schema management", "externalDocs" : { "description" : "Specification", "url" : "https://hyperledger.github.io/anoncreds-spec" } }, { - "name" : "anoncreds - wallet upgrade", - "description" : "Anoncreds wallet upgrade", + "name" : "AnonCreds - Wallet Upgrade", + "description" : "AnonCreds wallet upgrade", "externalDocs" : { "description" : "Specification", "url" : "https://hyperledger.github.io/anoncreds-spec" } + }, { + "name" : "action-menu", + "description" : "Menu interaction over connection" }, { "name" : "basicmessage", "description" : "Simple messaging", @@ -435,7 +435,7 @@ "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/AnoncredsRevocationModuleResponse" + "$ref" : "#/definitions/AnonCredsRevocationModuleResponse" } } } @@ -458,7 +458,7 @@ "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/AnoncredsRevocationModuleResponse" + "$ref" : "#/definitions/AnonCredsRevocationModuleResponse" } } } @@ -497,7 +497,7 @@ "name" : "body", "required" : false, "schema" : { - "$ref" : "#/definitions/RevRegCreateRequestSchemaAnoncreds" + "$ref" : "#/definitions/RevRegCreateRequestSchemaAnonCreds" } } ], "responses" : { @@ -512,7 +512,7 @@ }, "/anoncreds/revocation/active-registry/{cred_def_id}" : { "get" : { - "tags" : [ "anoncreds - revocation" ], + "tags" : [ "AnonCreds - Revocation" ], "summary" : "Get current active revocation registry by credential definition id", "produces" : [ "application/json" ], "parameters" : [ { @@ -527,7 +527,7 @@ "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/RevRegResultSchemaAnoncreds" + "$ref" : "#/definitions/RevRegResultSchemaAnonCreds" } } } @@ -535,7 +535,7 @@ }, "/anoncreds/revocation/active-registry/{cred_def_id}/rotate" : { "post" : { - "tags" : [ "anoncreds - revocation" ], + "tags" : [ "AnonCreds - Revocation" ], "summary" : "Rotate revocation registry", "produces" : [ "application/json" ], "parameters" : [ { @@ -550,7 +550,7 @@ "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/RevRegsCreatedSchemaAnoncreds" + "$ref" : "#/definitions/RevRegsCreatedSchemaAnonCreds" } } } @@ -558,7 +558,7 @@ }, "/anoncreds/revocation/credential-record" : { "get" : { - "tags" : [ "anoncreds - revocation" ], + "tags" : [ "AnonCreds - Revocation" ], "summary" : "Get credential revocation status", "produces" : [ "application/json" ], "parameters" : [ { @@ -587,7 +587,7 @@ "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/CredRevRecordResultSchemaAnoncreds" + "$ref" : "#/definitions/CredRevRecordResultSchemaAnonCreds" } } } @@ -595,7 +595,7 @@ }, "/anoncreds/revocation/publish-revocations" : { "post" : { - "tags" : [ "anoncreds - revocation" ], + "tags" : [ "AnonCreds - Revocation" ], "summary" : "Publish pending revocations to ledger", "produces" : [ "application/json" ], "parameters" : [ { @@ -603,14 +603,14 @@ "name" : "body", "required" : false, "schema" : { - "$ref" : "#/definitions/PublishRevocationsSchemaAnoncreds" + "$ref" : "#/definitions/PublishRevocationsSchemaAnonCreds" } } ], "responses" : { "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/PublishRevocationsResultSchemaAnoncreds" + "$ref" : "#/definitions/PublishRevocationsResultSchemaAnonCreds" } } } @@ -618,7 +618,7 @@ }, "/anoncreds/revocation/registries" : { "get" : { - "tags" : [ "anoncreds - revocation" ], + "tags" : [ "AnonCreds - Revocation" ], "summary" : "Search for matching revocation registries that current agent created", "produces" : [ "application/json" ], "parameters" : [ { @@ -640,7 +640,7 @@ "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/RevRegsCreatedSchemaAnoncreds" + "$ref" : "#/definitions/RevRegsCreatedSchemaAnonCreds" } } } @@ -648,7 +648,7 @@ }, "/anoncreds/revocation/registry/{rev_reg_id}" : { "get" : { - "tags" : [ "anoncreds - revocation" ], + "tags" : [ "AnonCreds - Revocation" ], "summary" : "Get revocation registry by revocation registry id", "produces" : [ "application/json" ], "parameters" : [ { @@ -663,7 +663,7 @@ "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/RevRegResultSchemaAnoncreds" + "$ref" : "#/definitions/RevRegResultSchemaAnonCreds" } } } @@ -671,7 +671,7 @@ }, "/anoncreds/revocation/registry/{rev_reg_id}/fix-revocation-entry-state" : { "put" : { - "tags" : [ "anoncreds - revocation" ], + "tags" : [ "AnonCreds - Revocation" ], "summary" : "Fix revocation state in wallet and return number of updated entries", "produces" : [ "application/json" ], "parameters" : [ { @@ -692,7 +692,7 @@ "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/RevRegWalletUpdatedResultSchemaAnoncreds" + "$ref" : "#/definitions/RevRegWalletUpdatedResultSchemaAnonCreds" } } } @@ -700,7 +700,7 @@ }, "/anoncreds/revocation/registry/{rev_reg_id}/issued" : { "get" : { - "tags" : [ "anoncreds - revocation" ], + "tags" : [ "AnonCreds - Revocation" ], "summary" : "Get number of credentials issued against revocation registry", "produces" : [ "application/json" ], "parameters" : [ { @@ -715,7 +715,7 @@ "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/RevRegIssuedResultSchemaAnoncreds" + "$ref" : "#/definitions/RevRegIssuedResultSchemaAnonCreds" } } } @@ -723,7 +723,7 @@ }, "/anoncreds/revocation/registry/{rev_reg_id}/issued/details" : { "get" : { - "tags" : [ "anoncreds - revocation" ], + "tags" : [ "AnonCreds - Revocation" ], "summary" : "Get details of credentials issued against revocation registry", "produces" : [ "application/json" ], "parameters" : [ { @@ -738,7 +738,7 @@ "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/CredRevRecordDetailsResultSchemaAnoncreds" + "$ref" : "#/definitions/CredRevRecordDetailsResultSchemaAnonCreds" } } } @@ -746,7 +746,7 @@ }, "/anoncreds/revocation/registry/{rev_reg_id}/issued/indy_recs" : { "get" : { - "tags" : [ "anoncreds - revocation" ], + "tags" : [ "AnonCreds - Revocation" ], "summary" : "Get details of revoked credentials from ledger", "produces" : [ "application/json" ], "parameters" : [ { @@ -761,7 +761,7 @@ "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/CredRevIndyRecordsResultSchemaAnoncreds" + "$ref" : "#/definitions/CredRevIndyRecordsResultSchemaAnonCreds" } } } @@ -769,7 +769,7 @@ }, "/anoncreds/revocation/registry/{rev_reg_id}/set-state" : { "patch" : { - "tags" : [ "anoncreds - revocation" ], + "tags" : [ "AnonCreds - Revocation" ], "summary" : "Set revocation registry state manually", "produces" : [ "application/json" ], "parameters" : [ { @@ -791,7 +791,7 @@ "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/RevRegResultSchemaAnoncreds" + "$ref" : "#/definitions/RevRegResultSchemaAnonCreds" } } } @@ -799,7 +799,7 @@ }, "/anoncreds/revocation/registry/{rev_reg_id}/tails-file" : { "get" : { - "tags" : [ "anoncreds - revocation" ], + "tags" : [ "AnonCreds - Revocation" ], "summary" : "Download tails file", "produces" : [ "application/octet-stream" ], "parameters" : [ { @@ -814,7 +814,7 @@ "200" : { "description" : "tails file", "schema" : { - "$ref" : "#/definitions/AnoncredsRevocationModuleResponse" + "$ref" : "#/definitions/AnonCredsRevocationModuleResponse" } } } @@ -822,7 +822,7 @@ }, "/anoncreds/revocation/revoke" : { "post" : { - "tags" : [ "anoncreds - revocation" ], + "tags" : [ "AnonCreds - Revocation" ], "summary" : "Revoke an issued credential", "produces" : [ "application/json" ], "parameters" : [ { @@ -830,14 +830,14 @@ "name" : "body", "required" : false, "schema" : { - "$ref" : "#/definitions/RevokeRequestSchemaAnoncreds" + "$ref" : "#/definitions/RevokeRequestSchemaAnonCreds" } } ], "responses" : { "200" : { "description" : "", "schema" : { - "$ref" : "#/definitions/AnoncredsRevocationModuleResponse" + "$ref" : "#/definitions/AnonCredsRevocationModuleResponse" } } } @@ -3755,6 +3755,29 @@ } } }, + "/out-of-band/invitations" : { + "get" : { + "tags" : [ "out-of-band" ], + "summary" : "Fetch an existing Out-of-Band invitation.", + "produces" : [ "application/json" ], + "parameters" : [ { + "name" : "oob_id", + "in" : "query", + "description" : "The Out of Band id to fetch", + "required" : true, + "type" : "string", + "pattern" : "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}" + } ], + "responses" : { + "200" : { + "description" : "", + "schema" : { + "$ref" : "#/definitions/InvitationRecordResponse" + } + } + } + } + }, "/out-of-band/invitations/{invi_msg_id}" : { "delete" : { "tags" : [ "out-of-band" ], @@ -6380,37 +6403,7 @@ } } }, - "AnonCredsSchema" : { - "type" : "object", - "required" : [ "attrNames", "issuerId", "name", "version" ], - "properties" : { - "attrNames" : { - "type" : "array", - "description" : "Schema attribute names", - "items" : { - "type" : "string", - "example" : "score", - "description" : "Attribute name" - } - }, - "issuerId" : { - "type" : "string", - "example" : "did:(method):WgWxqztrNooG92RXvxSTWv", - "description" : "Issuer Identifier of the credential definition or schema" - }, - "name" : { - "type" : "string", - "example" : "Example schema", - "description" : "Schema name" - }, - "version" : { - "type" : "string", - "example" : "1.0", - "description" : "Schema version" - } - } - }, - "AnoncredsPresSpec" : { + "AnonCredsPresSpec" : { "type" : "object", "required" : [ "requested_attributes", "requested_predicates", "self_attested_attributes" ], "properties" : { @@ -6418,14 +6411,14 @@ "type" : "object", "description" : "Nested object mapping proof request attribute referents to requested-attribute specifiers", "additionalProperties" : { - "$ref" : "#/definitions/AnoncredsRequestedCredsRequestedAttr" + "$ref" : "#/definitions/AnonCredsRequestedCredsRequestedAttr" } }, "requested_predicates" : { "type" : "object", "description" : "Nested object mapping proof request predicate referents to requested-predicate specifiers", "additionalProperties" : { - "$ref" : "#/definitions/AnoncredsRequestedCredsRequestedPred" + "$ref" : "#/definitions/AnonCredsRequestedCredsRequestedPred" } }, "self_attested_attributes" : { @@ -6444,7 +6437,7 @@ } } }, - "AnoncredsPresentationReqAttrSpec" : { + "AnonCredsPresentationReqAttrSpec" : { "type" : "object", "properties" : { "name" : { @@ -6461,7 +6454,7 @@ } }, "non_revoked" : { - "$ref" : "#/definitions/AnoncredsPresentationReqAttrSpecNonRevoked" + "$ref" : "#/definitions/AnonCredsPresentationReqAttrSpecNonRevoked" }, "restrictions" : { "type" : "array", @@ -6476,7 +6469,7 @@ } } }, - "AnoncredsPresentationReqAttrSpecNonRevoked" : { + "AnonCredsPresentationReqAttrSpecNonRevoked" : { "type" : "object", "properties" : { "from" : { @@ -6495,7 +6488,7 @@ } } }, - "AnoncredsPresentationReqPredSpec" : { + "AnonCredsPresentationReqPredSpec" : { "type" : "object", "required" : [ "name", "p_type", "p_value" ], "properties" : { @@ -6505,7 +6498,7 @@ "description" : "Attribute name" }, "non_revoked" : { - "$ref" : "#/definitions/AnoncredsPresentationReqPredSpecNonRevoked" + "$ref" : "#/definitions/AnonCredsPresentationReqPredSpecNonRevoked" }, "p_type" : { "type" : "string", @@ -6530,7 +6523,7 @@ } } }, - "AnoncredsPresentationReqPredSpecNonRevoked" : { + "AnonCredsPresentationReqPredSpecNonRevoked" : { "type" : "object", "properties" : { "from" : { @@ -6549,7 +6542,7 @@ } } }, - "AnoncredsPresentationRequest" : { + "AnonCredsPresentationRequest" : { "type" : "object", "required" : [ "requested_attributes", "requested_predicates" ], "properties" : { @@ -6559,7 +6552,7 @@ "description" : "Proof request name" }, "non_revoked" : { - "$ref" : "#/definitions/AnoncredsPresentationRequestNonRevoked" + "$ref" : "#/definitions/AnonCredsPresentationRequestNonRevoked" }, "nonce" : { "type" : "string", @@ -6571,14 +6564,14 @@ "type" : "object", "description" : "Requested attribute specifications of proof request", "additionalProperties" : { - "$ref" : "#/definitions/AnoncredsPresentationReqAttrSpec" + "$ref" : "#/definitions/AnonCredsPresentationReqAttrSpec" } }, "requested_predicates" : { "type" : "object", "description" : "Requested predicate specifications of proof request", "additionalProperties" : { - "$ref" : "#/definitions/AnoncredsPresentationReqPredSpec" + "$ref" : "#/definitions/AnonCredsPresentationReqPredSpec" } }, "version" : { @@ -6589,7 +6582,7 @@ } } }, - "AnoncredsPresentationRequestNonRevoked" : { + "AnonCredsPresentationRequestNonRevoked" : { "type" : "object", "properties" : { "from" : { @@ -6608,7 +6601,7 @@ } } }, - "AnoncredsRequestedCredsRequestedAttr" : { + "AnonCredsRequestedCredsRequestedAttr" : { "type" : "object", "required" : [ "cred_id" ], "properties" : { @@ -6623,7 +6616,7 @@ } } }, - "AnoncredsRequestedCredsRequestedPred" : { + "AnonCredsRequestedCredsRequestedPred" : { "type" : "object", "required" : [ "cred_id" ], "properties" : { @@ -6641,9 +6634,39 @@ } } }, - "AnoncredsRevocationModuleResponse" : { + "AnonCredsRevocationModuleResponse" : { "type" : "object" }, + "AnonCredsSchema" : { + "type" : "object", + "required" : [ "attrNames", "issuerId", "name", "version" ], + "properties" : { + "attrNames" : { + "type" : "array", + "description" : "Schema attribute names", + "items" : { + "type" : "string", + "example" : "score", + "description" : "Attribute name" + } + }, + "issuerId" : { + "type" : "string", + "example" : "did:(method):WgWxqztrNooG92RXvxSTWv", + "description" : "Issuer Identifier of the credential definition or schema" + }, + "name" : { + "type" : "string", + "example" : "Example schema", + "description" : "Schema name" + }, + "version" : { + "type" : "string", + "example" : "1.0", + "description" : "Schema version" + } + } + }, "AttachDecorator" : { "type" : "object", "required" : [ "data" ], @@ -7382,7 +7405,7 @@ "enum" : [ "CL" ] }, "value" : { - "$ref" : "#/definitions/CredDefValueSchemaAnoncreds" + "$ref" : "#/definitions/CredDefValueSchemaAnonCreds" } } }, @@ -7497,7 +7520,7 @@ } } }, - "CredDefValuePrimarySchemaAnoncreds" : { + "CredDefValuePrimarySchemaAnonCreds" : { "type" : "object", "properties" : { "n" : { @@ -7575,7 +7598,7 @@ } } }, - "CredDefValueRevocationSchemaAnoncreds" : { + "CredDefValueRevocationSchemaAnonCreds" : { "type" : "object", "properties" : { "g" : { @@ -7624,7 +7647,7 @@ } } }, - "CredDefValueSchemaAnoncreds" : { + "CredDefValueSchemaAnonCreds" : { "type" : "object", "properties" : { "primary" : { @@ -7656,7 +7679,7 @@ } } }, - "CredRevIndyRecordsResultSchemaAnoncreds" : { + "CredRevIndyRecordsResultSchemaAnonCreds" : { "type" : "object", "properties" : { "rev_reg_delta" : { @@ -7677,13 +7700,13 @@ } } }, - "CredRevRecordDetailsResultSchemaAnoncreds" : { + "CredRevRecordDetailsResultSchemaAnonCreds" : { "type" : "object", "properties" : { "results" : { "type" : "array", "items" : { - "$ref" : "#/definitions/IssuerCredRevRecordSchemaAnoncreds" + "$ref" : "#/definitions/IssuerCredRevRecordSchemaAnonCreds" } } } @@ -7696,11 +7719,11 @@ } } }, - "CredRevRecordResultSchemaAnoncreds" : { + "CredRevRecordResultSchemaAnonCreds" : { "type" : "object", "properties" : { "result" : { - "$ref" : "#/definitions/IssuerCredRevRecordSchemaAnoncreds" + "$ref" : "#/definitions/IssuerCredRevRecordSchemaAnonCreds" } } }, @@ -10083,7 +10106,7 @@ } } }, - "IssuerCredRevRecordSchemaAnoncreds" : { + "IssuerCredRevRecordSchemaAnonCreds" : { "type" : "object", "properties" : { "created_at" : { @@ -11232,7 +11255,7 @@ } } }, - "PublishRevocationsResultSchemaAnoncreds" : { + "PublishRevocationsResultSchemaAnonCreds" : { "type" : "object", "properties" : { "rrid2crid" : { @@ -11250,7 +11273,7 @@ } } }, - "PublishRevocationsSchemaAnoncreds" : { + "PublishRevocationsSchemaAnonCreds" : { "type" : "object", "properties" : { "options" : { @@ -11497,7 +11520,7 @@ } } }, - "RevRegCreateRequestSchemaAnoncreds" : { + "RevRegCreateRequestSchemaAnonCreds" : { "type" : "object", "properties" : { "options" : { @@ -11618,7 +11641,7 @@ } } }, - "RevRegIssuedResultSchemaAnoncreds" : { + "RevRegIssuedResultSchemaAnonCreds" : { "type" : "object", "properties" : { "result" : { @@ -11637,7 +11660,7 @@ } } }, - "RevRegResultSchemaAnoncreds" : { + "RevRegResultSchemaAnonCreds" : { "type" : "object", "properties" : { "result" : { @@ -11677,7 +11700,7 @@ } } }, - "RevRegWalletUpdatedResultSchemaAnoncreds" : { + "RevRegWalletUpdatedResultSchemaAnonCreds" : { "type" : "object", "properties" : { "accum_calculated" : { @@ -11711,7 +11734,7 @@ } } }, - "RevRegsCreatedSchemaAnoncreds" : { + "RevRegsCreatedSchemaAnonCreds" : { "type" : "object", "properties" : { "rev_reg_ids" : { @@ -11778,7 +11801,7 @@ } } }, - "RevokeRequestSchemaAnoncreds" : { + "RevokeRequestSchemaAnonCreds" : { "type" : "object", "properties" : { "comment" : { @@ -13813,7 +13836,7 @@ } } }, - "V20CredFilterAnoncreds" : { + "V20CredFilterAnonCreds" : { "type" : "object", "properties" : { "cred_def_id" : { diff --git a/scenarios/examples/anoncreds_issuance_and_revocation/docker-compose.yml b/scenarios/examples/anoncreds_issuance_and_revocation/docker-compose.yml index 6e0a757fbd..995e0ba4ce 100644 --- a/scenarios/examples/anoncreds_issuance_and_revocation/docker-compose.yml +++ b/scenarios/examples/anoncreds_issuance_and_revocation/docker-compose.yml @@ -40,7 +40,7 @@ - "3002:3001" command: > start - --label Holder-Anoncreds + --label Holder-AnonCreds --inbound-transport http 0.0.0.0 3000 --outbound-transport http --endpoint http://holder_anoncreds:3000 diff --git a/scenarios/examples/anoncreds_issuance_and_revocation/example.py b/scenarios/examples/anoncreds_issuance_and_revocation/example.py index 5d2cc1431f..a9f7c6b4e7 100644 --- a/scenarios/examples/anoncreds_issuance_and_revocation/example.py +++ b/scenarios/examples/anoncreds_issuance_and_revocation/example.py @@ -10,9 +10,7 @@ from acapy_controller import Controller from acapy_controller.logging import logging_to_stdout -from acapy_controller.models import ( - CreateWalletResponse, -) +from acapy_controller.models import CreateWalletResponse from acapy_controller.protocols import ( DIDResult, didexchange, @@ -21,8 +19,8 @@ ) from aiohttp import ClientSession from examples.util import ( - CredDefResultAnoncreds, - SchemaResultAnoncreds, + CredDefResultAnonCreds, + SchemaResultAnonCreds, anoncreds_issue_credential_v2, anoncreds_present_proof_v2, ) @@ -127,7 +125,7 @@ async def main(): holder_anoncreds, issuer_conn_with_anoncreds_holder.connection_id, holder_anoncreds_conn.connection_id, - {"firstname": "Anoncreds", "lastname": "Holder"}, + {"firstname": "AnonCreds", "lastname": "Holder"}, cred_def_id=cred_def.credential_definition_id, issuer_id=public_did.did, schema_id=schema.schema_id, @@ -181,7 +179,7 @@ async def main(): holder_anoncreds, issuer_conn_with_anoncreds_holder.connection_id, holder_anoncreds_conn.connection_id, - {"firstname": "Anoncreds", "lastname": "Holder"}, + {"firstname": "AnonCreds", "lastname": "Holder"}, cred_def_id=cred_def.credential_definition_id, issuer_id=public_did.did, schema_id=schema.schema_id, @@ -361,7 +359,7 @@ async def main(): "issuerId": public_did.did, } }, - response=SchemaResultAnoncreds, + response=SchemaResultAnonCreds, ) cred_def = await issuer.post( "/anoncreds/credential-definition", @@ -373,7 +371,7 @@ async def main(): }, "options": {"support_revocation": True, "revocation_registry_size": 10}, }, - response=CredDefResultAnoncreds, + response=CredDefResultAnonCreds, ) # Issue a new credential to anoncreds holder @@ -382,7 +380,7 @@ async def main(): holder_anoncreds, issuer_conn_with_anoncreds_holder.connection_id, holder_anoncreds_conn.connection_id, - {"middlename": "Anoncreds"}, + {"middlename": "AnonCreds"}, cred_def_id=cred_def.credential_definition_state["credential_definition_id"], issuer_id=public_did.did, schema_id=schema.schema_state["schema_id"], @@ -522,14 +520,14 @@ async def main(): }, "options": {"support_revocation": True, "revocation_registry_size": 10}, }, - response=CredDefResultAnoncreds, + response=CredDefResultAnonCreds, ) issuer_cred_ex, _ = await anoncreds_issue_credential_v2( issuer_without_schema, holder_anoncreds, issuer_conn_with_anoncreds_holder.connection_id, holder_anoncreds_conn.connection_id, - {"middlename": "Anoncreds"}, + {"middlename": "AnonCreds"}, cred_def_id=cred_def.credential_definition_state["credential_definition_id"], schema_id=schema.schema_state["schema_id"], ) diff --git a/scenarios/examples/mediation/example.py b/scenarios/examples/mediation/example.py index f4c84fdc51..3de69ad703 100644 --- a/scenarios/examples/mediation/example.py +++ b/scenarios/examples/mediation/example.py @@ -8,11 +8,7 @@ from acapy_controller import Controller from acapy_controller.logging import logging_to_stdout -from acapy_controller.protocols import ( - didexchange, - request_mediation_v1, - trustping, -) +from acapy_controller.protocols import didexchange, request_mediation_v1, trustping ALICE = getenv("ALICE", "http://alice:3001") BOB = getenv("BOB", "http://bob:3001") diff --git a/scenarios/examples/restart_anoncreds_upgrade/example.py b/scenarios/examples/restart_anoncreds_upgrade/example.py index ee1305f969..cc272c1d11 100644 --- a/scenarios/examples/restart_anoncreds_upgrade/example.py +++ b/scenarios/examples/restart_anoncreds_upgrade/example.py @@ -314,13 +314,13 @@ async def main(): Controller(base_url=ALICE) as alice, Controller(base_url=BOB_ANONCREDS) as bob, ): - # connect to Bob (Anoncreds wallet) and issue (and revoke) some credentials + # connect to Bob (AnonCreds wallet) and issue (and revoke) some credentials (alice_conn, bob_conn) = await connect_agents_and_issue_credentials( alice, bob, cred_def, "Bob", - "Anoncreds", + "AnonCreds", ) alice_conns["anoncreds"] = alice_conn bob_conns["anoncreds"] = bob_conn @@ -427,7 +427,7 @@ async def main(): bob, cred_def, "Bob", - "Anoncreds", + "AnonCreds", inviter_conn=alice_conns["anoncreds"], invitee_conn=bob_conns["anoncreds"], ) diff --git a/scenarios/examples/simple_restart/example.py b/scenarios/examples/simple_restart/example.py index 17597dce6b..3727568da9 100644 --- a/scenarios/examples/simple_restart/example.py +++ b/scenarios/examples/simple_restart/example.py @@ -16,9 +16,7 @@ indy_issue_credential_v2, indy_present_proof_v2, ) -from examples.util import ( - wait_until_healthy, -) +from examples.util import wait_until_healthy import docker diff --git a/scenarios/examples/util.py b/scenarios/examples/util.py index afd165cb99..8374078fb1 100644 --- a/scenarios/examples/util.py +++ b/scenarios/examples/util.py @@ -7,11 +7,7 @@ from acapy_controller import Controller from acapy_controller.controller import Minimal, MinType -from acapy_controller.models import ( - V20CredExRecordIndy, - V20PresExRecord, -) - +from acapy_controller.models import V20CredExRecordIndy, V20PresExRecord from docker.models.containers import Container @@ -77,14 +73,14 @@ def anoncreds_presentation_summary(presentation: V20PresExRecord) -> str: @dataclass -class SchemaResultAnoncreds(Minimal): +class SchemaResultAnonCreds(Minimal): """Schema result.""" schema_state: dict @dataclass -class CredDefResultAnoncreds(Minimal): +class CredDefResultAnonCreds(Minimal): """Credential definition result.""" credential_definition_state: dict From 8a83571ade6c018ec399d9ca166a44ba509bdce9 Mon Sep 17 00:00:00 2001 From: Mourits de Beer <31511766+ff137@users.noreply.github.com> Date: Mon, 14 Apr 2025 10:50:07 +0200 Subject: [PATCH 76/76] :art: Replace print statements in Banner with info log (#3643) --- acapy_agent/config/banner.py | 102 ++++++++++++--------- acapy_agent/config/logging/configurator.py | 9 +- acapy_agent/config/tests/test_logging.py | 15 +-- acapy_agent/core/conductor.py | 2 + 4 files changed, 71 insertions(+), 57 deletions(-) diff --git a/acapy_agent/config/banner.py b/acapy_agent/config/banner.py index 6d60d682c6..efe06a5228 100644 --- a/acapy_agent/config/banner.py +++ b/acapy_agent/config/banner.py @@ -1,19 +1,29 @@ """Module to contain logic to generate the banner for ACA-py.""" -import sys +import logging import textwrap from contextlib import contextmanager from enum import Enum, auto from typing import Optional, TextIO +logger = logging.getLogger(__name__) + @contextmanager def Banner(border: str, length: int, file: Optional[TextIO] = None): """Context manager to generate a banner for ACA-py.""" banner = _Banner(border, length, file) - banner.print_border() + banner.add_border() yield banner - banner.print_border() + banner.add_border() + + # Join all lines with newlines and log them + banner_text = "\n".join(banner.lines) + banner_text = f"\n{banner_text.strip()}\n" # Start/end with a newline + if file: + print(banner_text, file=file) + else: + logger.info(banner_text) class _Banner: @@ -34,11 +44,12 @@ def __init__(self, border: str, length: int, file: Optional[TextIO] = None): """ self.border = border self.length = length - self.file = file or sys.stdout + self.file = file + self.lines = [] - def _print(self, text: str): - """Print value.""" - print(text, file=self.file) + def _add_line(self, text: str): + """Add a line to the banner.""" + self.lines.append(text) def _lr_pad(self, content: str): """Pad string content with defined border character. @@ -48,80 +59,87 @@ def _lr_pad(self, content: str): """ return f"{self.border}{self.border} {content} {self.border}{self.border}" - def _print_line(self, text: str, alignment: align = align.LEFT): - """Print line.""" + def _format_line(self, text: str, alignment: align = align.LEFT): + """Format a line with the specified alignment.""" lines = textwrap.wrap(text, width=self.length) + formatted_lines = [] + for line in lines: if len(line) < self.length: if alignment == self.align.LEFT: - left = "" - right = " " * (self.length - len(line)) + # Left alignment + formatted_line = f"{line:<{self.length}}" elif alignment == self.align.CENTER: - left = " " * ((self.length - len(line)) // 2) - right = " " * ((self.length - len(line)) // 2) - if len(line) % 2 != 0: - right += " " + # Center alignment + total_padding = self.length - len(line) + left_padding = total_padding // 2 + right_padding = total_padding - left_padding + formatted_line = f"{' ' * left_padding}{line}{' ' * right_padding}" elif alignment == self.align.RIGHT: - left = " " * (self.length - len(line)) - right = "" + # Right alignment + formatted_line = f"{line:>{self.length}}" else: raise ValueError(f"Invalid alignment: {alignment}") - line = f"{left}{line}{right}" - self._print(self._lr_pad(line)) + else: + formatted_line = line + + formatted_lines.append(self._lr_pad(formatted_line)) + + return formatted_lines - def print_border(self): - """Print a full line using the border character.""" - self._print(self.border * (self.length + 6)) + def add_border(self): + """Add a full line using the border character.""" + self._add_line(self.border * (self.length + 6)) def title(self, title, spacing_after: int = 2): - """Print the main title element.""" - self._print_line(title, self.align.CENTER) + """Add the main title element.""" + self.lines.extend(self._format_line(title, self.align.CENTER)) for _ in range(spacing_after): self.spacer() def spacer(self): - """Print an empty line with the border character only.""" - self._print(self._lr_pad(" " * self.length)) + """Add an empty line with the border character only.""" + self._add_line(self._lr_pad(" " * self.length)) def hr(self, char: str = "-"): - """Print a line with a horizontal rule.""" - self._print(self._lr_pad(char * self.length)) + """Add a line with a horizontal rule.""" + self._add_line(self._lr_pad(char * self.length)) def subtitle(self, title: str, spacing_after: int = 1): - """Print a subtitle for a section.""" + """Add a subtitle for a section.""" title += ":" - self._print_line(title, self.align.LEFT) + self.lines.extend(self._format_line(title, self.align.LEFT)) for _ in range(spacing_after): self.spacer() def list(self, items, spacing_after: int = 1): - """Print a list of items, prepending a dash to each item.""" + """Add a list of items, prepending a dash to each item.""" for item in items: - self._print_line(f" - {item}", self.align.LEFT) + self.lines.extend(self._format_line(f" - {item}", self.align.LEFT)) for _ in range(spacing_after): self.spacer() def version(self, version): - """Print the current ``version``.""" + """Add the current ``version``.""" version = f"ver: {version}" - self._print_line(version, self.align.RIGHT) + self.lines.extend(self._format_line(version, self.align.RIGHT)) def print(self, text: str): - """Print a line of text.""" - self._print_line(text, self.align.LEFT) + """Add a line of text.""" + self.lines.extend(self._format_line(text, self.align.LEFT)) def left(self, text: str): - """Print a line of text left aligned. + """Add a line of text left aligned. Same as `print` method. """ - self._print_line(text, self.align.LEFT) + self.lines.extend(self._format_line(text, self.align.LEFT)) def centered(self, text: str): - """Print a line of text centered.""" - self._print_line(text, self.align.CENTER) + """Add a line of text centered.""" + self.lines.extend(self._format_line(text, self.align.CENTER)) def right(self, text: str): - """Print a line of text right aligned.""" - self._print_line(text, self.align.RIGHT) + """Add a line of text right aligned.""" + self.lines.extend(self._format_line(text, self.align.RIGHT)) diff --git a/acapy_agent/config/logging/configurator.py b/acapy_agent/config/logging/configurator.py index 5f7de2e37e..a02cbb4851 100644 --- a/acapy_agent/config/logging/configurator.py +++ b/acapy_agent/config/logging/configurator.py @@ -5,7 +5,6 @@ import logging import logging.config import os -import sys from importlib import resources from logging.config import ( _clearExistingHandlers, @@ -286,7 +285,6 @@ def print_banner( border_character: (Default value = ":") Character to use in banner border """ - print() with Banner(border=border_character, length=banner_length) as banner: # Title banner.title(agent_label or "ACA") @@ -348,14 +346,10 @@ def print_banner( banner.version(__version__) - print() - print("Listening...") - print() - @classmethod def print_notices(cls, settings: Settings): """Print notices and warnings.""" - with Banner(border=":", length=80, file=sys.stderr) as banner: + with Banner(border=":", length=80) as banner: if settings.get("wallet.type", "in_memory").lower() == "indy": banner.centered("⚠ DEPRECATION NOTICE: ⚠") banner.hr() @@ -392,4 +386,3 @@ def print_notices(cls, settings: Settings): "and support will be removed in a future release; " "use RFC 0454: Present Proof 2.0 instead." ) - print() diff --git a/acapy_agent/config/tests/test_logging.py b/acapy_agent/config/tests/test_logging.py index 0f027b2124..0b94c8764b 100644 --- a/acapy_agent/config/tests/test_logging.py +++ b/acapy_agent/config/tests/test_logging.py @@ -1,5 +1,4 @@ -import contextlib -from io import BufferedReader, StringIO, TextIOWrapper +from io import BufferedReader, TextIOWrapper from tempfile import NamedTemporaryFile from unittest import IsolatedAsyncioTestCase, mock @@ -87,13 +86,13 @@ def test_configure_with_multitenant_with_yaml_file(self): ) def test_banner_did(self): - stdout = StringIO() mock_http = mock.MagicMock(scheme="http", host="1.2.3.4", port=8081) mock_https = mock.MagicMock(schemes=["https", "archie"]) mock_admin_server = mock.MagicMock(host="1.2.3.4", port=8091) - with contextlib.redirect_stdout(stdout): - test_label = "Aries Cloud Agent" - test_did = "55GkHamhTU1ZbTbV2ab9DE" + test_label = "Aries Cloud Agent" + test_did = "55GkHamhTU1ZbTbV2ab9DE" + + with self.assertLogs(level="INFO") as log: test_module.LoggingConfigurator.print_banner( test_label, {"in": mock_http}, @@ -104,7 +103,9 @@ def test_banner_did(self): test_module.LoggingConfigurator.print_banner( test_label, {"in": mock_http}, {"out": mock_https}, test_did ) - output = stdout.getvalue() + + # Join all log records and check if DID is present + output = "\n".join(log.output) assert test_did in output def test_load_resource(self): diff --git a/acapy_agent/core/conductor.py b/acapy_agent/core/conductor.py index ca6252d5b0..6b7623b361 100644 --- a/acapy_agent/core/conductor.py +++ b/acapy_agent/core/conductor.py @@ -592,6 +592,8 @@ async def start(self) -> None: await self.root_profile.notify(STARTUP_EVENT_TOPIC, {}) LOGGER.debug("Startup notification sent.") + LOGGER.info("Listening...") + async def stop(self, timeout=1.0): """Stop the agent.""" LOGGER.info("Stopping the Conductor agent.")