Skip to content

Commit

Permalink
Merge pull request #904 from jamshale/owl-issue/872
Browse files Browse the repository at this point in the history
Anoncreds issuance/presentation and connections v1 plugin
  • Loading branch information
swcurran authored Feb 11, 2025
2 parents 08d9c8e + 4e27679 commit c56d925
Show file tree
Hide file tree
Showing 22 changed files with 263 additions and 76 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test-harness-acapy-aip10.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
with:
BUILD_AGENTS: "-a acapy-main"
TEST_AGENTS: "-d acapy-main"
TEST_SCOPE: "-t @AcceptanceTest -t @AIP10,@RFC0211 -t ~@wip -t ~@T004-RFC0211 -t ~@Transport_NoHttpOutbound"
TEST_SCOPE: "-t @AcceptanceTest -t @AIP10,@RFC0211 -t ~@wip -t ~@T004-RFC0211 -t ~@Transport_NoHttpOutbound -t ~@Anoncreds"
REPORT_PROJECT: acapy-aip10
- name: run-send-gen-test-results-secure
if: ${{ steps.run_test_harness.conclusion == 'success' }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-harness-acapy-aip20.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
with:
BUILD_AGENTS: "-a acapy-main"
TEST_AGENTS: "-d acapy-main"
TEST_SCOPE: "-t @AcceptanceTest -t @AIP20 -t ~@wip -t ~@T004-RFC0211 -t ~@Transport_NoHttpOutbound -t ~@DidMethod_orb"
TEST_SCOPE: "-t @AcceptanceTest -t @AIP20 -t ~@wip -t ~@T004-RFC0211 -t ~@Transport_NoHttpOutbound -t ~@DidMethod_orb -t ~@Anoncreds"
REPORT_PROJECT: acapy-aip20
- name: run-send-gen-test-results-secure
if: ${{ steps.run_test_harness.conclusion == 'success' }}
Expand Down
54 changes: 54 additions & 0 deletions .github/workflows/test-harness-acapy-anoncreds.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: test-harness-acapy-acapy
# RUNSET_NAME: "ACA-PY to ACA-Py"
# Scope: AIP 1.0
# Exceptions: None
# SKIP
#
# Summary
#
# This runset uses the current main branch of ACA-Py for all of the agents. The runset runs all of the tests in the suite
# that are expected to pass given the current state of ACA-Py support for AIP 1 and 2.
#
# Current
#
# All of the tests being executed in this runset are passing.
#
# *Status Note Updated: 2021.03.18*
#
# End
on:
workflow_dispatch:
defaults:
run:
shell: bash
jobs:
test:
runs-on: ubuntu-latest
env:
LEDGER_URL_CONFIG: "http://localhost:9000"
TAILS_SERVER_URL_CONFIG: "http://localhost:6543"
steps:
- name: checkout-test-harness
uses: actions/checkout@v4
with:
path: test-harness
- name: run-von-network
uses: ./test-harness/actions/run-von-network
- name: run-indy-tails-server
uses: ./test-harness/actions/run-indy-tails-server
- name: run-test-harness-wo-reports
id: run_test_harness
uses: ./test-harness/actions/run-test-harness-wo-reports
with:
BUILD_AGENTS: "-a acapy-main"
TEST_AGENTS: "-d acapy-main"
TEST_SCOPE: "-t @AcceptanceTest -t ~@wip -t ~@T004-RFC0211 -t ~@DidMethod_orb -t ~@Transport_NoHttpOutbound -t ~@Indy -t ~@CredFormat_Indy"
REPORT_PROJECT: acapy
- name: run-send-gen-test-results-secure
if: ${{ steps.run_test_harness.conclusion == 'success' }}
uses: ./test-harness/actions/run-send-gen-test-results-secure
with:
REPORT_PROJECT: acapy-anoncreds
ADMIN_USER: ${{ secrets.AllureAdminUser }}
ADMIN_PW: ${{ secrets.AllureAdminPW }}
BACKCHANNEL_EXTRA_acapy_main: "{\"wallet-type\":\"askar-anoncreds\"}"
2 changes: 1 addition & 1 deletion .github/workflows/test-harness-acapy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
with:
BUILD_AGENTS: "-a acapy-main"
TEST_AGENTS: "-d acapy-main"
TEST_SCOPE: "-t @AcceptanceTest -t ~@wip -t ~@T004-RFC0211 -t ~@DidMethod_orb -t ~@Transport_NoHttpOutbound"
TEST_SCOPE: "-t @AcceptanceTest -t ~@wip -t ~@T004-RFC0211 -t ~@DidMethod_orb -t ~@Transport_NoHttpOutbound -t ~@Anoncreds"
REPORT_PROJECT: acapy
- name: run-send-gen-test-results-secure
if: ${{ steps.run_test_harness.conclusion == 'success' }}
Expand Down
1 change: 1 addition & 0 deletions aries-backchannels/acapy/Dockerfile.acapy-main
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ RUN chmod +x ./jq
COPY python/requirements.txt python/
COPY acapy/requirements-main.txt acapy/
RUN pip install -r python/requirements.txt -r acapy/requirements-main.txt
RUN pip install git+https://github.com/openwallet-foundation/acapy-plugins@main#subdirectory=connections

# Copy the necessary files from the AATH Backchannel sub-folders
COPY python python
Expand Down
82 changes: 71 additions & 11 deletions aries-backchannels/acapy/acapy_backchannel.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,11 @@ def __init__(
"proof-v2": "/present-proof-2.0/",
}

self.credFormatFilterTranslationDict = {"indy": "indy", "json-ld": "ld_proof"}
self.credFormatFilterTranslationDict = {
"indy": "indy",
"json-ld": "ld_proof",
"anoncreds": "anoncreds",
}

self.proofTypeKeyTypeTranslationDict = {
"Ed25519Signature2018": "ed25519",
Expand Down Expand Up @@ -178,6 +182,13 @@ def __init__(
"active": "completed",
}

def is_wallet_anoncreds(self):
return self.wallet_type == "askar-anoncreds"

def use_anoncreds(self, command):
anoncreds = self.is_wallet_anoncreds() or command.anoncreds
return anoncreds

def get_acapy_version_as_float(self):
# construct some number to compare to with > or < instead of listing out the version number
# if it starts with zero strip it off
Expand Down Expand Up @@ -230,6 +241,8 @@ def get_agent_args(self):
"--open-mediation",
"--enable-undelivered-queue",
"--preserve-exchange-records", # For AATH purposes, exchange records must be retained -- not typical in production
"--plugin",
"connections",
]

# Backchannel needs to handle operations that may be called in the protocol by the tests
Expand All @@ -256,6 +269,7 @@ def get_agent_args(self):
result.append(("--genesis-transactions", self.genesis_data))
if self.seed:
result.append(("--seed", self.seed))
# deprecated - should be removed
if self.storage_type:
result.append(("--storage-type", self.storage_type))
if self.postgres:
Expand Down Expand Up @@ -298,6 +312,8 @@ def get_agent_args(self):
# when it does (and there is talk of supporting YAML) then this code can be removed.
if os.getenv("LOG_LEVEL") is not None:
result.append(("--log-level", os.getenv("LOG_LEVEL")))
else:
result.append(("--log-level", "ERROR"))

# aca-py supports a config.yaml file to pass in arguments. This env var point to such a file.
if os.getenv("AGENT_CONFIG_FILE") is not None:
Expand Down Expand Up @@ -491,9 +507,10 @@ async def handle_out_of_band(self, message: Mapping[str, Any]):
push_resource(invitation_id, "out-of-band-msg", message)

async def handle_problem_report(self, message: Mapping[str, Any]):
thread_id = message["thread_id"]
push_resource(thread_id, "problem-report-msg", message)
log_msg("Received Problem Report Webhook message: " + json.dumps(message, indent=4))
thread_id = message.get("thread_id")
if thread_id:
push_resource(thread_id, "problem-report-msg", message)

async def swap_thread_id_for_exchange_id(
self,
Expand Down Expand Up @@ -685,8 +702,24 @@ async def make_agent_POST_request(
return (resp_status, resp_text)

elif command.topic == "schema":
# check command type vs agent wallet type - can we support "anoncreds" tests?
if self.use_anoncreds(command):
if not self.is_wallet_anoncreds():
return (400, "Bad request - agent wallet cannot support anoncreds format")

# POST operation is to create a new schema
if command.anoncreds:
if self.use_anoncreds(command):
# make sure our "data" is in the correct format
if not "schema" in data:
new_data = {
"schema": {
"issuerId": data.get("issuer_id"),
"name": data.get("schema_name"),
"version": data.get("schema_version"),
"attrNames": data.get("attributes"),
}
}
data = new_data
schema_name = data['schema'].get("name")
schema_version = data['schema'].get("version")
schema_get_endpoint = '/anoncreds/schemas'
Expand All @@ -696,6 +729,9 @@ async def make_agent_POST_request(
schema_version = data.get("schema_version")
schema_get_endpoint = '/schemas/created'
schema_post_endpoint = '/schemas'
# not needed for "legacy" indy schemas
if "issuer_id" in data:
del data["issuer_id"]

# Check if schema id already exists
log_msg(schema_post_endpoint, data)
Expand All @@ -718,8 +754,25 @@ async def make_agent_POST_request(
return (resp_status, resp_text)

elif command.topic == "credential-definition":
# check command type vs agent wallet type - can we support "anoncreds" tests?
if self.use_anoncreds(command):
if not self.is_wallet_anoncreds():
return (400, "Bad request - agent wallet cannot support anoncreds format")

# POST operation is to create a new cred def
if command.anoncreds:
if self.use_anoncreds(command):
if not "credential_definition" in data:
new_data = {
"credential_definition": {
"schemaId": data.get("schema_id"),
"issuerId": data.get("issuer_id"),
"tag": data.get("tag"),
"options": {
"support_revocation": data.get("support_revocation"),
},
}
}
data = new_data
schema_id = data['credential_definition'].get("schemaId")
tag = data['credential_definition'].get("tag")
cred_defs_get_endpoint = '/anoncreds/credential-definitions'
Expand All @@ -729,6 +782,9 @@ async def make_agent_POST_request(
schema_id = data.get("schema_id")
cred_defs_get_endpoint = '/credential-definitions/created'
cred_defs_post_endpoint = '/credential-definitions'
# not needed for "legacy" indy cred defs
if "issuer_id" in data:
del data["issuer_id"]

agent_operation = "/credential-definitions"
log_msg(agent_operation, json.dumps(command.data, indent=4))
Expand Down Expand Up @@ -1199,6 +1255,8 @@ async def handle_issue_credential_v2_POST(self, command: BackchannelCommand):
record_id = command.record_id
data = command.data

log_msg(">>> got issue_cred message:", operation, topic, json.dumps(data, indent=4))

if (
self.auto_respond_credential_proposal
and operation == "send-offer"
Expand Down Expand Up @@ -1323,6 +1381,8 @@ async def handle_proof_v2_POST(self, command: BackchannelCommand):
record_id = command.record_id
data = command.data

log_msg(f">>> in handle_proof_v2_POST(): {operation} {topic} {record_id} {data}")

if (
self.auto_respond_presentation_proposal
and operation == "send-request"
Expand Down Expand Up @@ -1492,7 +1552,7 @@ async def make_agent_GET_request(

elif command.topic == "schema":
schema_id = record_id
if command.anoncreds:
if self.use_anoncreds(command):
agent_operation = f"/anoncreds/schema/{schema_id}"
else:
agent_operation = f"/schemas/{schema_id}"
Expand All @@ -1505,7 +1565,7 @@ async def make_agent_GET_request(
schema = resp_json["schema"]

# If anoncreds, add the id to the schema to use existing framework
if command.anoncreds:
if self.use_anoncreds(command):
schema["id"] = resp_json["schema_id"]

resp_text = json.dumps(schema)
Expand All @@ -1514,7 +1574,7 @@ async def make_agent_GET_request(
elif command.topic == "credential-definition":
cred_def_id = record_id

if command.anoncreds:
if self.use_anoncreds(command):
agent_operation = f"/anoncreds/credential-definition/{cred_def_id}"
else:
agent_operation = f"/credential-definitions/{cred_def_id}"
Expand All @@ -1527,7 +1587,7 @@ async def make_agent_GET_request(
credential_definition = resp_json["credential_definition"]

# If anoncreds, add the id to the credential definition to use existing framework
if command.anoncreds:
if self.use_anoncreds(command):
credential_definition["id"] = resp_json["credential_definition_id"]

resp_text = json.dumps(credential_definition)
Expand Down Expand Up @@ -2080,7 +2140,7 @@ def map_test_json_to_admin_api_json(

if cred_format is None:
raise Exception("Credential format not specified for presentation")
elif cred_format == "indy":
elif cred_format == "indy" or cred_format == "anoncreds":
requested_attributes = pres_request_data.get(
"requested_attributes", {}
)
Expand Down Expand Up @@ -2125,7 +2185,7 @@ def map_test_json_to_admin_api_json(

if cred_format is None:
raise Exception("Credential format not specified for presentation")
elif cred_format == "indy":
elif cred_format == "indy" or cred_format == "anoncreds":
requested_attributes = data.get("requested_attributes", {})
requested_predicates = data.get("requested_predicates", {})
self_attested_attributes = data.get("self_attested_attributes", {})
Expand Down
2 changes: 1 addition & 1 deletion aries-backchannels/python/agent_backchannel.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ async def backchannel_middleware(request: web.Request, handler: Handler):

self.admin_url = f"http://{self.internal_host}:" + str(agent_ports["admin"])

self.storage_type = "askar"
self.storage_type = "askar" # deprecated - should be removed
self.wallet_type = (
extra_args.get("wallet-type") if extra_args.get("wallet-type") else "askar"
)
Expand Down
24 changes: 23 additions & 1 deletion aries-test-harness/agent_test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def format_cred_proposal_by_aip_version(
filters = amend_filters_with_runtime_data(context, filters, did_for_id)
credential_proposal = {
"credential_preview": {
"@type": "issue-credential/2.0/credential-preview",
"@type": "https://didcomm.org/issue-credential/2.0/credential-preview",
"attributes": cred_data,
},
"filter": filters,
Expand Down Expand Up @@ -105,6 +105,28 @@ def amend_filters_with_runtime_data(context, filters, did_for_id=None):
):
filters["indy"]["schema_id"] = context.issuer_schema_dict[schema_name]["id"]

if "anoncreds" in filters:
if (
"schema_issuer_did" in filters["anoncreds"]
and filters["anoncreds"]["schema_issuer_did"] == "replace_me"
):
filters["anoncreds"]["schema_issuer_did"] = context.issuer_did_dict[schema_name]
if (
"issuer_did" in filters["anoncreds"]
and filters["anoncreds"]["issuer_did"] == "replace_me"
):
filters["anoncreds"]["issuer_did"] = context.issuer_did_dict[schema_name]
if (
"cred_def_id" in filters["anoncreds"]
and filters["anoncreds"]["cred_def_id"] == "replace_me"
):
filters["anoncreds"]["cred_def_id"] = context.issuer_credential_definition_dict[schema_name]["id"]
if (
"schema_id" in filters["anoncreds"]
and filters["anoncreds"]["schema_id"] == "replace_me"
):
filters["anoncreds"]["schema_id"] = context.issuer_schema_dict[schema_name]["id"]

if "json-ld" in filters:
json_ld = filters.get("json-ld")
credential = json_ld.get("credential")
Expand Down
4 changes: 2 additions & 2 deletions aries-test-harness/features/0036-issue-credential.feature
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Feature: RFC 0036 Aries agent issue credential
And "Bob" acknowledges the credential issue
Then "Bob" has the credential issued

@T005-RFC0036 @AIP10 @minor @wip @AcceptanceTest
@T005-RFC0036 @AIP10 @minor @wip @AcceptanceTest @Indy
Scenario: Issue a credential with negotiation beginning from a credential request
Given "2" agents
| name | role |
Expand All @@ -92,7 +92,7 @@ Feature: RFC 0036 Aries agent issue credential
And "Bob" acknowledges the credential issue
Then "Bob" has the credential issued

@T006-RFC0036 @AIP10 @critical @wip @AcceptanceTest
@T006-RFC0036 @AIP10 @critical @wip @AcceptanceTest @Indy
Scenario: Issue a credential with the Holder beginning with a request and is accepted
Given "2" agents
| name | role |
Expand Down
2 changes: 1 addition & 1 deletion aries-test-harness/features/0037-present-proof.feature
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Feature: RFC 0037 Aries agent present proof
| Faber | Data_BI_HealthValues | proof_request_health_consent | presentation_health_consent |


@T001.5-RFC0037 @AIP10 @critical @AcceptanceTest @MobileTest
@T001.5-RFC0037 @AIP10 @critical @AcceptanceTest @MobileTest @Indy
Scenario Outline: Present Proof where the prover does not propose a presentation of the proof and is acknowledged
Given "2" agents
| name | role |
Expand Down
Loading

0 comments on commit c56d925

Please sign in to comment.