Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions .github/workflows/scenario-integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
test:
runs-on: ubuntu-latest
# Run on openwallet-foundation and non-draft PRs or on non-PR events
if: (github.repository == 'openwallet-foundation/acapy') && ((github.event_name == 'pull_request' && github.event.pull_request.draft == false) || (github.event_name != 'pull_request'))
if: (github.repository == 'jamshale/acapy') && ((github.event_name == 'pull_request' && github.event.pull_request.draft == false) || (github.event_name != 'pull_request'))
steps:
- name: checkout-acapy
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
Expand Down Expand Up @@ -61,8 +61,25 @@ jobs:
- name: Run Scenario Tests
if: steps.check-if-scenarios-or-src-changed.outputs.run_tests != 'false'
run: |
# Build the docker image for testing
set -euo pipefail

docker build -t acapy-test -f docker/Dockerfile.run .

cd scenarios
poetry install --no-root
poetry run pytest -m examples

for examples_file in $(find examples -type f -name 'example.py'); do
examples_dir=$(dirname "$examples_file")
echo -e "\n🔎 Running scenario in: $examples_dir"
cd "$examples_dir"
docker compose build
docker compose up -d
if ! docker compose run --rm example; then
echo "❌ Tests failed for $examples_dir - dumping logs:"
docker compose logs
docker compose down --remove-orphans
exit 1
fi
echo "✅ Tests passed for $examples_dir"
docker compose down --remove-orphans
cd - > /dev/null
done
70 changes: 36 additions & 34 deletions acapy_agent/anoncreds/revocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -993,46 +993,48 @@ def _has_required_id_and_tails_path():
rev_list = None

if _has_required_id_and_tails_path():
async with self.profile.session() as session:
rev_reg_def = await session.handle.fetch(
CATEGORY_REV_REG_DEF, rev_reg_def_id
)
rev_list = await session.handle.fetch(CATEGORY_REV_LIST, rev_reg_def_id)
rev_key = await session.handle.fetch(
# We need to make sure the read, index increment, and write
# operations on the revocation list are atomic.
# This is done by using a transaction.
async with self.profile.transaction() as txn:
rev_reg_def = await txn.handle.fetch(CATEGORY_REV_REG_DEF, rev_reg_def_id)
rev_list = await txn.handle.fetch(CATEGORY_REV_LIST, rev_reg_def_id)
rev_key = await txn.handle.fetch(
CATEGORY_REV_REG_DEF_PRIVATE, rev_reg_def_id
)

_handle_missing_entries(rev_list, rev_reg_def, rev_key)
_handle_missing_entries(rev_list, rev_reg_def, rev_key)

rev_list_value_json = rev_list.value_json
rev_list_tags = rev_list.tags
rev_list_value_json = rev_list.value_json
rev_list_tags = rev_list.tags

# If the rev_list state is failed then the tails file was never uploaded,
# try to upload it now and finish the revocation list
if rev_list_tags.get("state") == RevListState.STATE_FAILED:
await self.upload_tails_file(
RevRegDef.deserialize(rev_reg_def.value_json)
)
rev_list_tags["state"] = RevListState.STATE_FINISHED

rev_reg_index = rev_list_value_json["next_index"]
try:
rev_reg_def = RevocationRegistryDefinition.load(rev_reg_def.raw_value)
rev_list = RevocationStatusList.load(rev_list_value_json["rev_list"])
except AnoncredsError as err:
raise AnonCredsRevocationError(
"Error loading revocation registry"
) from err
# If the rev_list state is failed then the tails file was never uploaded,
# try to upload it now and finish the revocation list
if rev_list_tags.get("state") == RevListState.STATE_FAILED:
await self.upload_tails_file(
RevRegDef.deserialize(rev_reg_def.value_json)
)
rev_list_tags["state"] = RevListState.STATE_FINISHED

# NOTE: we increment the index ahead of time to keep the
# transaction short. The revocation registry itself will NOT
# be updated because we always use ISSUANCE_BY_DEFAULT.
# If something goes wrong later, the index will be skipped.
# FIXME - double check issuance type in case of upgraded wallet?
if rev_reg_index > rev_reg_def.max_cred_num:
raise AnonCredsRevocationRegistryFullError("Revocation registry is full")
rev_list_value_json["next_index"] = rev_reg_index + 1
async with self.profile.transaction() as txn:
rev_reg_index = rev_list_value_json["next_index"]
try:
rev_reg_def = RevocationRegistryDefinition.load(rev_reg_def.raw_value)
rev_list = RevocationStatusList.load(rev_list_value_json["rev_list"])
except AnoncredsError as err:
raise AnonCredsRevocationError(
"Error loading revocation registry"
) from err

# NOTE: we increment the index ahead of time to keep the
# transaction short. The revocation registry itself will NOT
# be updated because we always use ISSUANCE_BY_DEFAULT.
# If something goes wrong later, the index will be skipped.
# FIXME - double check issuance type in case of upgraded wallet?
if rev_reg_index > rev_reg_def.max_cred_num:
raise AnonCredsRevocationRegistryFullError(
"Revocation registry is full"
)
rev_list_value_json["next_index"] = rev_reg_index + 1
await txn.handle.replace(
CATEGORY_REV_LIST,
rev_reg_def_id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"""

import asyncio
import sys
from datetime import datetime
from os import getenv
from secrets import token_hex
Expand Down Expand Up @@ -555,4 +556,8 @@ async def main():

if __name__ == "__main__":
logging_to_stdout()
asyncio.run(main())
try:
asyncio.run(main())
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
144 changes: 144 additions & 0 deletions scenarios/examples/clustered/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@

services:
nginx:
image: nginx:latest
container_name: test_nginx
ports:
- "8080:80" # Host:Container for Admin API
- "5000:5000" # Host:Container for didcomm
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- faber
- alice
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 10s
timeout: 5s
retries: 5
start_period: 15s

faber:
image: acapy-test
ports:
- "4000"
deploy:
replicas: 3
restart: unless-stopped # Due to askar store race condition. Can remove if that's fixed.
command: >
start
--label Faber
--inbound-transport http 0.0.0.0 3000
--outbound-transport http
--endpoint http://nginx:5000
--admin 0.0.0.0 4000
--admin-insecure-mode
--tails-server-base-url http://tails:6543
--genesis-url http://test.bcovrin.vonx.io/genesis
--wallet-type askar-anoncreds
--wallet-name faber
--wallet-key insecure
--wallet-storage-type "postgres_storage"
--wallet-storage-config "{\"url\":\"wallet-db:5432\",\"max_connections\":5}"
--wallet-storage-creds "{\"account\":\"DB_USER\",\"password\":\"DB_PASSWORD\",\"admin_account\":\"DB_USER\",\"admin_password\":\"DB_PASSWORD\"}"
--auto-accept-invites
--auto-accept-requests
--auto-provision
--log-level info
--debug-webhooks
--notify-revocation
healthcheck:
test: curl -s -o /dev/null -w '%{http_code}' "http://localhost:4000/status/live" | grep "200" > /dev/null
start_period: 30s
interval: 7s
timeout: 5s
retries: 5
depends_on:
tails:
condition: service_started
wallet-db:
condition: service_healthy

alice:
image: acapy-test
ports:
- "6001:6001"
command: >
start
--label Alice
--inbound-transport http 0.0.0.0 6000
--outbound-transport http
--endpoint http://alice:6000
--admin 0.0.0.0 6001
--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
--auto-accept-invites
--auto-accept-requests
--log-level info
--debug-webhooks
--monitor-revocation-notification
healthcheck:
test: curl -s -o /dev/null -w '%{http_code}' "http://alice:6001/status/live" | grep "200" > /dev/null
start_period: 30s
interval: 7s
timeout: 5s
retries: 5
depends_on:
tails:
condition: service_started
wallet-db:
condition: service_healthy

example:
container_name: controller
build:
context: ../..
environment:
- FABER=http://nginx
- ALICE=http://alice:6001
volumes:
- ./example.py:/usr/src/app/example.py:ro,z
command: python -m example
depends_on:
faber:
condition: service_healthy
alice:
condition: service_healthy
wallet-db:
condition: service_healthy
nginx:
condition: service_started

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

wallet-db:
image: postgres:12
environment:
- POSTGRES_USER=DB_USER
- POSTGRES_PASSWORD=DB_PASSWORD
ports:
- 5433:5432
healthcheck:
test: ["CMD-SHELL", "pg_isready -U DB_USER"]
interval: 10s
retries: 5
start_period: 30s
timeout: 10s


Loading
Loading