Files
aitbc/cli/commands/compliance.py
aitbc1 5ca6a51862
Some checks failed
AITBC CI/CD Pipeline / lint-and-test (3.13.5) (push) Has been cancelled
AITBC CI/CD Pipeline / test-cli (push) Has been cancelled
AITBC CI/CD Pipeline / test-services (push) Has been cancelled
AITBC CI/CD Pipeline / test-production-services (push) Has been cancelled
AITBC CI/CD Pipeline / security-scan (push) Has been cancelled
AITBC CI/CD Pipeline / build (push) Has been cancelled
AITBC CI/CD Pipeline / deploy-staging (push) Has been cancelled
AITBC CI/CD Pipeline / deploy-production (push) Has been cancelled
AITBC CI/CD Pipeline / performance-test (push) Has been cancelled
AITBC CI/CD Pipeline / docs (push) Has been cancelled
AITBC CI/CD Pipeline / release (push) Has been cancelled
AITBC CI/CD Pipeline / notify (push) Has been cancelled
GPU Benchmark CI / gpu-benchmark (3.13.5) (push) Has been cancelled
Security Scanning / Bandit Security Scan (apps/coordinator-api/src) (push) Has been cancelled
Security Scanning / Bandit Security Scan (cli/aitbc_cli) (push) Has been cancelled
Security Scanning / Bandit Security Scan (packages/py/aitbc-core/src) (push) Has been cancelled
Security Scanning / Bandit Security Scan (packages/py/aitbc-crypto/src) (push) Has been cancelled
Security Scanning / Bandit Security Scan (packages/py/aitbc-sdk/src) (push) Has been cancelled
Security Scanning / Bandit Security Scan (tests) (push) Has been cancelled
Security Scanning / CodeQL Security Analysis (javascript) (push) Has been cancelled
Security Scanning / CodeQL Security Analysis (python) (push) Has been cancelled
Security Scanning / Dependency Security Scan (push) Has been cancelled
Security Scanning / Container Security Scan (push) Has been cancelled
Security Scanning / OSSF Scorecard (push) Has been cancelled
Security Scanning / Security Summary Report (push) Has been cancelled
AITBC CLI Level 1 Commands Test / test-cli-level1 (3.13.5) (push) Has been cancelled
AITBC CLI Level 1 Commands Test / test-summary (push) Has been cancelled
reorganize: sort CLI root files into logical subdirectories and rewire imports
DIRECTORY REORGANIZATION:
- Organized 13 scattered root files into 4 logical subdirectories
- Eliminated clutter in CLI root directory
- Improved maintainability and navigation

FILE MOVES:
core/ (Core CLI functionality):
├── __init__.py          # Package metadata
├── main.py              # Main CLI entry point
├── imports.py           # Import utilities
└── plugins.py           # Plugin system

utils/ (Utilities & Services):
├── dual_mode_wallet_adapter.py
├── wallet_daemon_client.py
├── wallet_migration_service.py
├── kyc_aml_providers.py
└── [other utility files]

docs/ (Documentation):
├── README.md
├── DISABLED_COMMANDS_CLEANUP.md
└── FILE_ORGANIZATION_SUMMARY.md

variants/ (CLI Variants):
└── main_minimal.py      # Minimal CLI version

REWIRED IMPORTS:
 Updated main.py: 'from .plugins import plugin, load_plugins'
 Updated 6 commands: 'from core.imports import ensure_coordinator_api_imports'
 Updated wallet.py: 'from utils.dual_mode_wallet_adapter import DualModeWalletAdapter'
 Updated compliance.py: 'from utils.kyc_aml_providers import ...'
 Fixed internal utils imports: 'from utils import error, success'
 Updated test files: 'from core.main_minimal import cli'
 Updated setup.py: entry point 'aitbc=core.main:main'
 Updated setup.py: README path 'docs/README.md'
 Created root __init__.py: redirects to core.main

BENEFITS:
 Logical file grouping by functionality
 Clean root directory with only essential files
 Easier navigation and maintenance
 Clear separation of concerns
 Better code organization
 Zero breaking changes - all functionality preserved

VERIFICATION:
 CLI works: 'aitbc --help' functional
 All imports resolve correctly
 Installation successful: 'pip install -e .'
 Entry points properly updated
 Tests import correctly

STATUS: Complete - Successfully organized and rewired
2026-03-26 09:24:48 +01:00

295 lines
12 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Compliance CLI Commands - KYC/AML Integration
Real compliance verification and monitoring commands
"""
import click
import asyncio
import json
from typing import Optional, Dict, Any
from datetime import datetime
# Import compliance providers
from utils.kyc_aml_providers import submit_kyc_verification, check_kyc_status, perform_aml_screening
@click.group()
def compliance():
"""Compliance and regulatory management commands"""
pass
@compliance.command()
@click.option("--user-id", required=True, help="User ID to verify")
@click.option("--provider", required=True, type=click.Choice(['chainalysis', 'sumsub', 'onfido', 'jumio', 'veriff']), help="KYC provider")
@click.option("--first-name", required=True, help="Customer first name")
@click.option("--last-name", required=True, help="Customer last name")
@click.option("--email", required=True, help="Customer email")
@click.option("--dob", help="Date of birth (YYYY-MM-DD)")
@click.option("--phone", help="Phone number")
@click.pass_context
def kyc_submit(ctx, user_id: str, provider: str, first_name: str, last_name: str, email: str, dob: str, phone: str):
"""Submit KYC verification request"""
try:
# Prepare customer data
customer_data = {
"first_name": first_name,
"last_name": last_name,
"email": email,
"date_of_birth": dob,
"phone": phone
}
# Remove None values
customer_data = {k: v for k, v in customer_data.items() if v is not None}
# Submit KYC
click.echo(f"🔍 Submitting KYC verification for user {user_id} to {provider}...")
result = asyncio.run(submit_kyc_verification(user_id, provider, customer_data))
click.echo(f"✅ KYC verification submitted successfully!")
click.echo(f"📋 Request ID: {result['request_id']}")
click.echo(f"👤 User ID: {result['user_id']}")
click.echo(f"🏢 Provider: {result['provider']}")
click.echo(f"📊 Status: {result['status']}")
click.echo(f"⚠️ Risk Score: {result['risk_score']:.3f}")
click.echo(f"📅 Submitted: {result['created_at']}")
except Exception as e:
click.echo(f"❌ KYC submission failed: {e}", err=True)
@compliance.command()
@click.option("--request-id", required=True, help="KYC request ID to check")
@click.option("--provider", required=True, type=click.Choice(['chainalysis', 'sumsub', 'onfido', 'jumio', 'veriff']), help="KYC provider")
@click.pass_context
def kyc_status(ctx, request_id: str, provider: str):
"""Check KYC verification status"""
try:
click.echo(f"🔍 Checking KYC status for request {request_id}...")
result = asyncio.run(check_kyc_status(request_id, provider))
# Status icons
status_icons = {
"pending": "",
"approved": "",
"rejected": "",
"failed": "💥",
"expired": ""
}
status_icon = status_icons.get(result['status'], "")
click.echo(f"{status_icon} KYC Status: {result['status'].upper()}")
click.echo(f"📋 Request ID: {result['request_id']}")
click.echo(f"👤 User ID: {result['user_id']}")
click.echo(f"🏢 Provider: {result['provider']}")
click.echo(f"⚠️ Risk Score: {result['risk_score']:.3f}")
if result.get('rejection_reason'):
click.echo(f"🚫 Rejection Reason: {result['rejection_reason']}")
click.echo(f"📅 Created: {result['created_at']}")
# Provide guidance based on status
if result['status'] == 'pending':
click.echo(f"\n💡 Verification is in progress. Check again later.")
elif result['status'] == 'approved':
click.echo(f"\n🎉 User is verified and can proceed with trading!")
elif result['status'] in ['rejected', 'failed']:
click.echo(f"\n⚠️ Verification failed. User may need to resubmit documents.")
except Exception as e:
click.echo(f"❌ KYC status check failed: {e}", err=True)
@compliance.command()
@click.option("--user-id", required=True, help="User ID to screen")
@click.option("--first-name", required=True, help="User first name")
@click.option("--last-name", required=True, help="User last name")
@click.option("--email", required=True, help="User email")
@click.option("--dob", help="Date of birth (YYYY-MM-DD)")
@click.option("--phone", help="Phone number")
@click.pass_context
def aml_screen(ctx, user_id: str, first_name: str, last_name: str, email: str, dob: str, phone: str):
"""Perform AML screening on user"""
try:
# Prepare user data
user_data = {
"first_name": first_name,
"last_name": last_name,
"email": email,
"date_of_birth": dob,
"phone": phone
}
# Remove None values
user_data = {k: v for k, v in user_data.items() if v is not None}
click.echo(f"🔍 Performing AML screening for user {user_id}...")
result = asyncio.run(perform_aml_screening(user_id, user_data))
# Risk level icons
risk_icons = {
"low": "🟢",
"medium": "🟡",
"high": "🟠",
"critical": "🔴"
}
risk_icon = risk_icons.get(result['risk_level'], "")
click.echo(f"{risk_icon} AML Risk Level: {result['risk_level'].upper()}")
click.echo(f"📊 Risk Score: {result['risk_score']:.3f}")
click.echo(f"👤 User ID: {result['user_id']}")
click.echo(f"🏢 Provider: {result['provider']}")
click.echo(f"📋 Check ID: {result['check_id']}")
click.echo(f"📅 Screened: {result['checked_at']}")
# Sanctions hits
if result['sanctions_hits']:
click.echo(f"\n🚨 SANCTIONS HITS FOUND:")
for hit in result['sanctions_hits']:
click.echo(f" • List: {hit['list']}")
click.echo(f" Name: {hit['name']}")
click.echo(f" Confidence: {hit['confidence']:.2%}")
else:
click.echo(f"\n✅ No sanctions hits found")
# Guidance based on risk level
if result['risk_level'] == 'critical':
click.echo(f"\n🚨 CRITICAL RISK: Immediate action required!")
elif result['risk_level'] == 'high':
click.echo(f"\n⚠️ HIGH RISK: Manual review recommended")
elif result['risk_level'] == 'medium':
click.echo(f"\n🟡 MEDIUM RISK: Monitor transactions closely")
else:
click.echo(f"\n✅ LOW RISK: User cleared for normal activity")
except Exception as e:
click.echo(f"❌ AML screening failed: {e}", err=True)
@compliance.command()
@click.option("--user-id", required=True, help="User ID for full compliance check")
@click.option("--first-name", required=True, help="User first name")
@click.option("--last-name", required=True, help="User last name")
@click.option("--email", required=True, help="User email")
@click.option("--dob", help="Date of birth (YYYY-MM-DD)")
@click.option("--phone", help="Phone number")
@click.option("--kyc-provider", default="chainalysis", type=click.Choice(['chainalysis', 'sumsub', 'onfido', 'jumio', 'veriff']), help="KYC provider")
@click.pass_context
def full_check(ctx, user_id: str, first_name: str, last_name: str, email: str, dob: str, phone: str, kyc_provider: str):
"""Perform full compliance check (KYC + AML)"""
try:
click.echo(f"🔍 Performing full compliance check for user {user_id}...")
click.echo(f"🏢 KYC Provider: {kyc_provider}")
click.echo()
# Prepare user data
user_data = {
"first_name": first_name,
"last_name": last_name,
"email": email,
"date_of_birth": dob,
"phone": phone
}
user_data = {k: v for k, v in user_data.items() if v is not None}
# Step 1: Submit KYC
click.echo("📋 Step 1: Submitting KYC verification...")
kyc_result = asyncio.run(submit_kyc_verification(user_id, kyc_provider, user_data))
click.echo(f"✅ KYC submitted: {kyc_result['request_id']}")
# Step 2: Check KYC status
click.echo("\n📋 Step 2: Checking KYC status...")
kyc_status = asyncio.run(check_kyc_status(kyc_result['request_id'], kyc_provider))
# Step 3: AML Screening
click.echo("\n🔍 Step 3: Performing AML screening...")
aml_result = asyncio.run(perform_aml_screening(user_id, user_data))
# Display comprehensive results
click.echo(f"\n{'='*60}")
click.echo(f"📊 COMPLIANCE CHECK SUMMARY")
click.echo(f"{'='*60}")
# KYC Results
kyc_icons = {"pending": "", "approved": "", "rejected": "", "failed": "💥"}
kyc_icon = kyc_icons.get(kyc_status['status'], "")
click.echo(f"\n{kyc_icon} KYC Verification:")
click.echo(f" Status: {kyc_status['status'].upper()}")
click.echo(f" Risk Score: {kyc_status['risk_score']:.3f}")
click.echo(f" Provider: {kyc_status['provider']}")
if kyc_status.get('rejection_reason'):
click.echo(f" Reason: {kyc_status['rejection_reason']}")
# AML Results
risk_icons = {"low": "🟢", "medium": "🟡", "high": "🟠", "critical": "🔴"}
aml_icon = risk_icons.get(aml_result['risk_level'], "")
click.echo(f"\n{aml_icon} AML Screening:")
click.echo(f" Risk Level: {aml_result['risk_level'].upper()}")
click.echo(f" Risk Score: {aml_result['risk_score']:.3f}")
click.echo(f" Sanctions Hits: {len(aml_result['sanctions_hits'])}")
# Overall Assessment
click.echo(f"\n📋 OVERALL ASSESSMENT:")
kyc_approved = kyc_status['status'] == 'approved'
aml_safe = aml_result['risk_level'] in ['low', 'medium']
if kyc_approved and aml_safe:
click.echo(f"✅ USER APPROVED FOR TRADING")
click.echo(f" ✅ KYC: Verified")
click.echo(f" ✅ AML: Safe")
elif not kyc_approved:
click.echo(f"❌ USER REJECTED")
click.echo(f" ❌ KYC: {kyc_status['status']}")
click.echo(f" AML: {aml_result['risk_level']}")
else:
click.echo(f"⚠️ USER REQUIRES MANUAL REVIEW")
click.echo(f" KYC: {kyc_status['status']}")
click.echo(f" ⚠️ AML: {aml_result['risk_level']} risk")
click.echo(f"\n{'='*60}")
except Exception as e:
click.echo(f"❌ Full compliance check failed: {e}", err=True)
@compliance.command()
@click.pass_context
def list_providers(ctx):
"""List all supported compliance providers"""
try:
click.echo("🏢 Supported KYC Providers:")
kyc_providers = [
("chainalysis", "Blockchain-focused KYC/AML"),
("sumsub", "Multi-channel verification"),
("onfido", "Document verification"),
("jumio", "Identity verification"),
("veriff", "Video-based verification")
]
for provider, description in kyc_providers:
click.echo(f"{provider.title()}: {description}")
click.echo(f"\n🔍 AML Screening:")
click.echo(f" • Chainalysis AML: Blockchain transaction analysis")
click.echo(f" • Sanctions List Screening: OFAC, UN, EU lists")
click.echo(f" • PEP Screening: Politically Exposed Persons")
click.echo(f" • Adverse Media: News and public records")
click.echo(f"\n📝 Usage Examples:")
click.echo(f" aitbc compliance kyc-submit --user-id user123 --provider chainalysis --first-name John --last-name Doe --email john@example.com")
click.echo(f" aitbc compliance aml-screen --user-id user123 --first-name John --last-name Doe --email john@example.com")
click.echo(f" aitbc compliance full-check --user-id user123 --first-name John --last-name Doe --email john@example.com")
except Exception as e:
click.echo(f"❌ Error listing providers: {e}", err=True)
if __name__ == "__main__":
compliance()