Skip to content

Commit

Permalink
Merge pull request #1643 from hyperledger/feat/accept-taa-args
Browse files Browse the repository at this point in the history
feat: accept taa using config
  • Loading branch information
andrewwhitehead authored Feb 24, 2022
2 parents e29e6ef + 7c241aa commit ecf2f28
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 18 deletions.
15 changes: 15 additions & 0 deletions aries_cloudagent/config/argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,18 @@ def add_arguments(self, parser: ArgumentParser):
" HyperLedger Indy ledgers."
),
)
parser.add_argument(
"--accept-taa",
type=str,
nargs=2,
metavar=("<acceptance-mechanism>", "<taa-version>"),
env_var="ACAPY_ACCEPT_TAA",
help=(
"Specify the acceptance mechanism and taa version for which to accept"
" the transaction author agreement. If not provided, the TAA must"
" be accepted through the TTY or the admin API."
),
)

def get_settings(self, args: Namespace) -> dict:
"""Extract ledger settings."""
Expand Down Expand Up @@ -838,6 +850,9 @@ def get_settings(self, args: Namespace) -> dict:
settings["ledger.keepalive"] = args.ledger_keepalive
if args.ledger_socks_proxy:
settings["ledger.socks_proxy"] = args.ledger_socks_proxy
if args.accept_taa:
settings["ledger.taa_acceptance_mechanism"] = args.accept_taa[0]
settings["ledger.taa_acceptance_version"] = args.accept_taa[1]

return settings

Expand Down
64 changes: 53 additions & 11 deletions aries_cloudagent/config/ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import logging
import re
import sys
from typing import Optional
import uuid

import markdown
Expand Down Expand Up @@ -140,7 +141,7 @@ async def ledger_config(
not taa_accepted
or taa_info["taa_record"]["digest"] != taa_accepted["digest"]
):
if not await accept_taa(ledger, taa_info, provision):
if not await accept_taa(ledger, profile, taa_info, provision):
return False

# Publish endpoints if necessary - skipped if TAA is required but not accepted
Expand All @@ -162,13 +163,8 @@ async def ledger_config(
return True


async def accept_taa(ledger: BaseLedger, taa_info, provision: bool = False) -> bool:
"""Perform TAA acceptance."""

if not sys.stdout.isatty():
LOGGER.warning("Cannot accept TAA without interactive terminal")
return False

async def select_aml_tty(taa_info, provision: bool = False) -> Optional[str]:
"""Select acceptance mechanism from AML."""
mechanisms = taa_info["aml_record"]["aml"]
allow_opts = OrderedDict(
[
Expand Down Expand Up @@ -230,16 +226,62 @@ async def accept_taa(ledger: BaseLedger, taa_info, provision: bool = False) -> b
try:
opt = await prompt_toolkit.prompt(opts_text, async_=True)
except EOFError:
return False
return None
if not opt:
opt = "1"
opt = opt.strip()
if opt in ("x", "X"):
return False
return None
if opt in num_mechanisms:
mechanism = num_mechanisms[opt]
break

await ledger.accept_txn_author_agreement(taa_info["taa_record"], mechanism)
return mechanism


async def accept_taa(
ledger: BaseLedger,
profile: Profile,
taa_info,
provision: bool = False,
) -> bool:
"""Perform TAA acceptance."""

mechanisms = taa_info["aml_record"]["aml"]
mechanism = None

taa_acceptance_mechanism = profile.settings.get("ledger.taa_acceptance_mechanism")
taa_acceptance_version = profile.settings.get("ledger.taa_acceptance_version")

# If configured, accept the TAA automatically
if taa_acceptance_mechanism:
taa_record_version = taa_info["taa_record"]["version"]
if taa_acceptance_version != taa_record_version:
raise LedgerError(
f"TAA version ({taa_record_version}) is different from TAA accept "
f"version ({taa_acceptance_version}) from configuration. Update the "
"TAA version in the config to accept the TAA."
)

if taa_acceptance_mechanism not in mechanisms:
raise LedgerError(
f"TAA acceptance mechanism '{taa_acceptance_mechanism}' is not a "
"valid acceptance mechanism. Valid mechanisms are: "
+ str(list(mechanisms.keys()))
)

mechanism = taa_acceptance_mechanism
# If tty is available use it (allows to accept newer TAA than configured)
elif sys.stdout.isatty():
mechanism = await select_aml_tty(taa_info, provision)
else:
LOGGER.warning(
"Cannot accept TAA without interactive terminal or taa accept config"
)

if not mechanism:
return False

LOGGER.debug(f"Accepting the TAA using mechanism '{mechanism}'")
await ledger.accept_txn_author_agreement(taa_info["taa_record"], mechanism)
return True
73 changes: 66 additions & 7 deletions aries_cloudagent/config/tests/test_ledger.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from os import remove
from tempfile import NamedTemporaryFile

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

from .. import argparse
Expand Down Expand Up @@ -643,14 +643,23 @@ async def test_load_multiple_genesis_transactions_from_config_io_x(self):
)

@async_mock.patch("sys.stdout")
async def test_ledger_accept_taa_not_tty(self, mock_stdout):
async def test_ledger_accept_taa_not_tty_not_accept_config(self, mock_stdout):
mock_stdout.isatty = async_mock.MagicMock(return_value=False)
mock_profile = InMemoryProfile.test_profile()

taa_info = {
"taa_record": {"version": "1.0", "text": "Agreement"},
"aml_record": {"aml": ["wallet_agreement", "on_file"]},
}

assert not await test_module.accept_taa(None, None, provision=False)
assert not await test_module.accept_taa(
None, mock_profile, taa_info, provision=False
)

@async_mock.patch("sys.stdout")
async def test_ledger_accept_taa(self, mock_stdout):
async def test_ledger_accept_taa_tty(self, mock_stdout):
mock_stdout.isatty = async_mock.MagicMock(return_value=True)
mock_profile = InMemoryProfile.test_profile()

taa_info = {
"taa_record": {"version": "1.0", "text": "Agreement"},
Expand All @@ -663,15 +672,19 @@ async def test_ledger_accept_taa(self, mock_stdout):
test_module.prompt_toolkit, "prompt", async_mock.CoroutineMock()
) as mock_prompt:
mock_prompt.side_effect = EOFError()
assert not await test_module.accept_taa(None, taa_info, provision=False)
assert not await test_module.accept_taa(
None, mock_profile, taa_info, provision=False
)

with async_mock.patch.object(
test_module, "use_asyncio_event_loop", async_mock.MagicMock()
) as mock_use_aio_loop, async_mock.patch.object(
test_module.prompt_toolkit, "prompt", async_mock.CoroutineMock()
) as mock_prompt:
mock_prompt.return_value = "x"
assert not await test_module.accept_taa(None, taa_info, provision=False)
assert not await test_module.accept_taa(
None, mock_profile, taa_info, provision=False
)

with async_mock.patch.object(
test_module, "use_asyncio_event_loop", async_mock.MagicMock()
Expand All @@ -682,7 +695,53 @@ async def test_ledger_accept_taa(self, mock_stdout):
accept_txn_author_agreement=async_mock.CoroutineMock()
)
mock_prompt.return_value = ""
assert await test_module.accept_taa(mock_ledger, taa_info, provision=False)
assert await test_module.accept_taa(
mock_ledger, mock_profile, taa_info, provision=False
)

async def test_ledger_accept_taa_tty(self):
taa_info = {
"taa_record": {"version": "1.0", "text": "Agreement"},
"aml_record": {"aml": {"wallet_agreement": "", "on_file": ""}},
}

# Incorrect version
with pytest.raises(LedgerError):
mock_profile = InMemoryProfile.test_profile(
{
"ledger.taa_acceptance_mechanism": "wallet_agreement",
"ledger.taa_acceptance_version": "1.5",
}
)
assert not await test_module.accept_taa(
None, mock_profile, taa_info, provision=False
)

# Incorrect mechanism
with pytest.raises(LedgerError):
mock_profile = InMemoryProfile.test_profile(
{
"ledger.taa_acceptance_mechanism": "not_exist",
"ledger.taa_acceptance_version": "1.0",
}
)
assert not await test_module.accept_taa(
None, mock_profile, taa_info, provision=False
)

# Valid
mock_profile = InMemoryProfile.test_profile(
{
"ledger.taa_acceptance_mechanism": "on_file",
"ledger.taa_acceptance_version": "1.0",
}
)
mock_ledger = async_mock.MagicMock(
accept_txn_author_agreement=async_mock.CoroutineMock()
)
assert await test_module.accept_taa(
mock_ledger, mock_profile, taa_info, provision=False
)

async def test_ledger_config(self):
"""Test required argument parsing."""
Expand Down

0 comments on commit ecf2f28

Please sign in to comment.