Skip to content

Commit

Permalink
Merge branch 'main' into feature/configurable-route-access
Browse files Browse the repository at this point in the history
  • Loading branch information
dbluhm committed Jun 24, 2022
2 parents 8d856c9 + dc476c0 commit 584c095
Show file tree
Hide file tree
Showing 31 changed files with 946 additions and 375 deletions.
36 changes: 22 additions & 14 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# 0.7.4-RC4
# 0.7.4-RC5

## June 21, 2022
## June 23, 2022

**NOTE** We expect 0.7.4-rc5 will the be the last Release Candidate prior to the
official 0.7.4 release.

**NOTE:** 0.7.4-rc4 contains a fix for a revocation-related issue introduced in
0.7.4-rc3. We recommend updating to 0.7.4-rc4 immediately if you have been using
Expand All @@ -11,18 +14,18 @@

The 0.7.4 release consists largely of internal fixes to ACA-Py, big increases in
performance resulting from the now recommended use of [Aries
Askar](https://github.com/bcgov/aries-askar) instead of the Indy-SDK, tools for
dealing with revocation-related issues, plus a number of enhancements. There have been
a lot of groups exercising ACA-Py and the updates made in this release are a
reflection of those efforts. We have PRs that have been contributed by 20
different people, which is likely a record for a single ACA-Py release.

The largest enhancement is in the area of the Hyperledger Indy endorser,
enabling an instance of ACA-Py to act as an Endorser for Indy authors needed
endorsing to write objects to an Indy ledger. We're hoping to see an
"aries-endorser-service" come from that work, an Endorser to be easily operated
by an organization, ideally with a controller starter kit to allow an approvals
business flow.
Askar](https://github.com/bcgov/aries-askar) instead of the Indy-SDK,
improvements and tools for dealing with revocation-related issues, plus a number
of general enhancements. There have been a lot of groups exercising ACA-Py and the
updates made in this release are a reflection of those efforts. We have PRs that
have been contributed by 21 different people.

The largest enhancement is in the area of the endorsing of Hyperledger Indy
ledger transactions, enabling an instance of ACA-Py to act as an Endorser for
Indy authors needing endorsements to write objects to an Indy ledger. We're
hoping to see (and working on!) an "aries-endorser-service" come from that work,
an Endorser to be easily operated by an organization, ideally with a controller
starter kit supporting a basic approvals business workflow.

A focus towards the end of the 0.7.4 development and release cycle was on the
handling of AnonCreds revocation in ACA-Py. Most important, a production issue
Expand Down Expand Up @@ -82,6 +85,7 @@ stuff needed for a growing codebase.
- Use provided connection_id if provided [\#1726](https://github.com/hyperledger/aries-cloudagent-python/pull/1726) ([ianco](https://github.com/ianco))

- Additions to the startup parameters, Admin API and Web Hooks
- Improve typing of settings and add plugin settings object [\#1833](https://github.com/hyperledger/aries-cloudagent-python/pull/1833) ([dbluhm](https://github.com/dbluhm))
- feat: accept taa using startup parameter --accept-taa [\#1643](https://github.com/hyperledger/aries-cloudagent-python/pull/1643) ([TimoGlastra](https://github.com/TimoGlastra))
- Add auto_verify flag in present-proof protocol [\#1702](https://github.com/hyperledger/aries-cloudagent-python/pull/1702) ([DaevMithran](https://github.com/DaevMithran))
- feat: query connections by their_public_did [\#1637](https://github.com/hyperledger/aries-cloudagent-python/pull/1637) ([TimoGlastra](https://github.com/TimoGlastra))
Expand Down Expand Up @@ -133,6 +137,7 @@ stuff needed for a growing codebase.

- Multitenacy updates and fixes
- feat: create new JWT tokens and invalidate older for multitenancy [\#1725](https://github.com/hyperledger/aries-cloudagent-python/pull/1725) ([TimoGlastra](https://github.com/TimoGlastra))
- Multi-tenancy stale wallet clean up [\#1692](https://github.com/hyperledger/aries-cloudagent-python/pull/1692) ([dbluhm](https://github.com/dbluhm))

- Dependencies and internal code updates/fixes
- Update pyjwt to 2.4 [\#1829](https://github.com/hyperledger/aries-cloudagent-python/pull/1829) ([andrewwhitehead](https://github.com/andrewwhitehead))
Expand Down Expand Up @@ -176,8 +181,11 @@ stuff needed for a growing codebase.
- Remove references to play with von [\#1688](https://github.com/hyperledger/aries-cloudagent-python/pull/1688) ([ianco](https://github.com/ianco))
- Add pre-commit as optional developer tool [\#1671](https://github.com/hyperledger/aries-cloudagent-python/pull/1671) ([dbluhm](https://github.com/dbluhm))
- run_docker start - pass environment variables [\#1715](https://github.com/hyperledger/aries-cloudagent-python/pull/1715) ([shaangill025](https://github.com/shaangill025))
- Use local deps only [\#1834](https://github.com/hyperledger/aries-cloudagent-python/pull/1834) ([ryjones](https://github.com/ryjones))
- Enable pip-audit [\#1831](https://github.com/hyperledger/aries-cloudagent-python/pull/1831) ([ryjones](https://github.com/ryjones))

- Release management pull requests
- 0.7.4-rc5 changelog, version and ReadTheDocs updates [\#1838](https://github.com/hyperledger/aries-cloudagent-python/pull/1838) ([swcurran](https://github.com/swcurran))
- Update changelog and version for 0.7.4-rc4 [\#1830](https://github.com/hyperledger/aries-cloudagent-python/pull/1830) ([swcurran](https://github.com/swcurran))
- Changelog, version and ReadTheDocs updates for 0.7.4-rc3 release [\#1817](https://github.com/hyperledger/aries-cloudagent-python/pull/1817) ([swcurran](https://github.com/swcurran))
- 0.7.4-rc2 update [\#1771](https://github.com/hyperledger/aries-cloudagent-python/pull/1771) ([swcurran](https://github.com/swcurran))
Expand Down
17 changes: 14 additions & 3 deletions aries_cloudagent/admin/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from typing import Callable, Coroutine, Optional, Pattern, Sequence, cast
import uuid
import warnings
import weakref

from aiohttp import web
from aiohttp_apispec import (
Expand Down Expand Up @@ -115,7 +116,11 @@ def __init__(
"""
super().__init__(**kwargs)
self._profile = profile
# Weakly hold the profile so this reference doesn't prevent profiles
# from being cleaned up when appropriate.
# Binding this AdminResponder to the profile's context creates a circular
# reference.
self._profile = weakref.ref(profile)
self._send = send

async def send_outbound(self, message: OutboundMessage) -> OutboundSendStatus:
Expand All @@ -125,7 +130,10 @@ async def send_outbound(self, message: OutboundMessage) -> OutboundSendStatus:
Args:
message: The `OutboundMessage` to be sent
"""
return await self._send(self._profile, message)
profile = self._profile()
if not profile:
raise RuntimeError("weakref to profile has expired")
return await self._send(profile, message)

async def send_webhook(self, topic: str, payload: dict):
"""
Expand All @@ -139,7 +147,10 @@ async def send_webhook(self, topic: str, payload: dict):
"responder.send_webhook is deprecated; please use the event bus instead.",
DeprecationWarning,
)
await self._profile.notify("acapy::webhook::" + topic, payload)
profile = self._profile()
if not profile:
raise RuntimeError("weakref to profile has expired")
await profile.notify("acapy::webhook::" + topic, payload)

@property
def send_fn(self) -> Coroutine:
Expand Down
17 changes: 15 additions & 2 deletions aries_cloudagent/admin/tests/test_admin_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,9 @@ async def test_import_routes_multitenant_middleware(self):
)
context.injector.bind_instance(ProtocolRegistry, ProtocolRegistry())
context.injector.bind_instance(GoalCodeRegistry, GoalCodeRegistry())
profile = InMemoryProfile.test_profile()
context.injector.bind_instance(
test_module.BaseMultitenantManager,
test_module.BaseMultitenantManager(profile),
async_mock.MagicMock(spec=test_module.BaseMultitenantManager),
)
await DefaultContextBuilder().load_plugins(context)
server = self.get_admin_server(
Expand Down Expand Up @@ -498,3 +497,17 @@ async def test_on_record_event(server, event_topic, webhook_topic):
) as mock_send_webhook:
await server._on_record_event(profile, Event(event_topic, None))
mock_send_webhook.assert_called_once_with(profile, webhook_topic, None)


@pytest.mark.asyncio
async def test_admin_responder_profile_expired_x():
def _smaller_scope():
profile = InMemoryProfile.test_profile()
return test_module.AdminResponder(profile, None)

responder = _smaller_scope()
with pytest.raises(RuntimeError):
await responder.send_outbound(None)

with pytest.raises(RuntimeError):
await responder.send_webhook("test", {})
18 changes: 12 additions & 6 deletions aries_cloudagent/askar/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,18 @@ class AskarProfile(Profile):

BACKEND_NAME = "askar"

def __init__(self, opened: AskarOpenStore, context: InjectionContext = None):
def __init__(
self,
opened: AskarOpenStore,
context: InjectionContext = None,
*,
profile_id: str = None
):
"""Create a new AskarProfile instance."""
super().__init__(context=context, name=opened.name, created=opened.created)
self.opened = opened
self.ledger_pool: IndyVdrLedgerPool = None
self.profile_id = profile_id
self.init_ledger_pool()
self.bind_providers()

Expand All @@ -56,8 +63,8 @@ def store(self) -> Store:

async def remove(self):
"""Remove the profile."""
if self.settings.get("multitenant.wallet_type") == "askar-profile":
await self.store.remove_profile(self.settings.get("wallet.askar_profile"))
if self.profile_id:
await self.store.remove_profile(self.profile_id)

def init_ledger_pool(self):
"""Initialize the ledger pool."""
Expand Down Expand Up @@ -160,11 +167,10 @@ def __init__(
):
"""Create a new IndySdkProfileSession instance."""
super().__init__(profile=profile, context=context, settings=settings)
profile_id = profile.context.settings.get("wallet.askar_profile")
if is_txn:
self._opener = self.profile.store.transaction(profile_id)
self._opener = self.profile.store.transaction(profile.profile_id)
else:
self._opener = self.profile.store.session(profile_id)
self._opener = self.profile.store.session(profile.profile_id)
self._handle: Session = None
self._acquire_start: float = None
self._acquire_end: float = None
Expand Down
155 changes: 78 additions & 77 deletions aries_cloudagent/askar/tests/test_profile.py
Original file line number Diff line number Diff line change
@@ -1,87 +1,88 @@
import asyncio
import logging
import pytest

from asynctest import TestCase as AsyncTestCase, mock
from asynctest import mock

from ...askar.profile import AskarProfile
from ...config.injection_context import InjectionContext

from .. import profile as test_module


class TestProfile(AsyncTestCase):
@mock.patch("aries_cloudagent.askar.store.AskarOpenStore")
async def test_init_success(self, AskarOpenStore):
askar_profile = AskarProfile(
AskarOpenStore,
)

assert askar_profile.opened == AskarOpenStore

@mock.patch("aries_cloudagent.askar.store.AskarOpenStore")
async def test_remove_success(self, AskarOpenStore):
openStore = AskarOpenStore
context = InjectionContext()
profile_id = "profile_id"
context.settings = {
"multitenant.wallet_type": "askar-profile",
"wallet.askar_profile": profile_id,
"ledger.genesis_transactions": mock.MagicMock(),
}
askar_profile = AskarProfile(openStore, context)
remove_profile_stub = asyncio.Future()
remove_profile_stub.set_result(True)
openStore.store.remove_profile.return_value = remove_profile_stub

await askar_profile.remove()

openStore.store.remove_profile.assert_called_once_with(profile_id)

@mock.patch("aries_cloudagent.askar.store.AskarOpenStore")
async def test_remove_profile_not_removed_if_wallet_type_not_askar_profile(
self, AskarOpenStore
):
openStore = AskarOpenStore
context = InjectionContext()
context.settings = {"multitenant.wallet_type": "basic"}
askar_profile = AskarProfile(openStore, context)

await askar_profile.remove()

openStore.store.remove_profile.assert_not_called()

@pytest.mark.asyncio
async def test_profile_manager_transaction(self):
profile = "profileId"

with mock.patch("aries_cloudagent.askar.profile.AskarProfile") as AskarProfile:
askar_profile = AskarProfile(None, True)
askar_profile_transaction = mock.MagicMock()
askar_profile.store.transaction.return_value = askar_profile_transaction
askar_profile.context.settings.get.return_value = profile

transactionProfile = test_module.AskarProfileSession(askar_profile, True)

assert transactionProfile._opener == askar_profile_transaction
askar_profile.context.settings.get.assert_called_once_with(
"wallet.askar_profile"
)
askar_profile.store.transaction.assert_called_once_with(profile)

@pytest.mark.asyncio
async def test_profile_manager_store(self):
profile = "profileId"

with mock.patch("aries_cloudagent.askar.profile.AskarProfile") as AskarProfile:
askar_profile = AskarProfile(None, False)
askar_profile_session = mock.MagicMock()
askar_profile.store.session.return_value = askar_profile_session
askar_profile.context.settings.get.return_value = profile

sessionProfile = test_module.AskarProfileSession(askar_profile, False)

assert sessionProfile._opener == askar_profile_session
askar_profile.context.settings.get.assert_called_once_with(
"wallet.askar_profile"
)
askar_profile.store.session.assert_called_once_with(profile)
@pytest.fixture
def open_store():
yield mock.MagicMock()


@pytest.mark.asyncio
async def test_init_success(open_store):
askar_profile = AskarProfile(
open_store,
)

assert askar_profile.opened == open_store


@pytest.mark.asyncio
async def test_remove_success(open_store):
openStore = open_store
context = InjectionContext()
profile_id = "profile_id"
context.settings = {
"multitenant.wallet_type": "askar-profile",
"wallet.askar_profile": profile_id,
"ledger.genesis_transactions": mock.MagicMock(),
}
askar_profile = AskarProfile(openStore, context, profile_id=profile_id)
remove_profile_stub = asyncio.Future()
remove_profile_stub.set_result(True)
openStore.store.remove_profile.return_value = remove_profile_stub

await askar_profile.remove()

openStore.store.remove_profile.assert_called_once_with(profile_id)


@pytest.mark.asyncio
async def test_remove_profile_not_removed_if_wallet_type_not_askar_profile(open_store):
openStore = open_store
context = InjectionContext()
context.settings = {"multitenant.wallet_type": "basic"}
askar_profile = AskarProfile(openStore, context)

await askar_profile.remove()

openStore.store.remove_profile.assert_not_called()


@pytest.mark.asyncio
async def test_profile_manager_transaction():
profile = "profileId"

with mock.patch("aries_cloudagent.askar.profile.AskarProfile") as AskarProfile:
askar_profile = AskarProfile(None, True, profile_id=profile)
askar_profile.profile_id = profile
askar_profile_transaction = mock.MagicMock()
askar_profile.store.transaction.return_value = askar_profile_transaction

transactionProfile = test_module.AskarProfileSession(askar_profile, True)

assert transactionProfile._opener == askar_profile_transaction
askar_profile.store.transaction.assert_called_once_with(profile)


@pytest.mark.asyncio
async def test_profile_manager_store():
profile = "profileId"

with mock.patch("aries_cloudagent.askar.profile.AskarProfile") as AskarProfile:
askar_profile = AskarProfile(None, False, profile_id=profile)
askar_profile.profile_id = profile
askar_profile_session = mock.MagicMock()
askar_profile.store.session.return_value = askar_profile_session

sessionProfile = test_module.AskarProfileSession(askar_profile, False)

assert sessionProfile._opener == askar_profile_session
askar_profile.store.session.assert_called_once_with(profile)
Loading

0 comments on commit 584c095

Please sign in to comment.