Files
claudetools/example_credential_import.py
Mike Swanson 390b10b32c Complete Phase 6: MSP Work Tracking with Context Recall System
Implements production-ready MSP platform with cross-machine persistent memory for Claude.

API Implementation:
- 130 REST API endpoints across 21 entities
- JWT authentication on all endpoints
- AES-256-GCM encryption for credentials
- Automatic audit logging
- Complete OpenAPI documentation

Database:
- 43 tables in MariaDB (172.16.3.20:3306)
- 42 SQLAlchemy models with modern 2.0 syntax
- Full Alembic migration system
- 99.1% CRUD test pass rate

Context Recall System (Phase 6):
- Cross-machine persistent memory via database
- Automatic context injection via Claude Code hooks
- Automatic context saving after task completion
- 90-95% token reduction with compression utilities
- Relevance scoring with time decay
- Tag-based semantic search
- One-command setup script

Security Features:
- JWT tokens with Argon2 password hashing
- AES-256-GCM encryption for all sensitive data
- Comprehensive audit trail for credentials
- HMAC tamper detection
- Secure configuration management

Test Results:
- Phase 3: 38/38 CRUD tests passing (100%)
- Phase 4: 34/35 core API tests passing (97.1%)
- Phase 5: 62/62 extended API tests passing (100%)
- Phase 6: 10/10 compression tests passing (100%)
- Overall: 144/145 tests passing (99.3%)

Documentation:
- Comprehensive architecture guides
- Setup automation scripts
- API documentation at /api/docs
- Complete test reports
- Troubleshooting guides

Project Status: 95% Complete (Production-Ready)
Phase 7 (optional work context APIs) remains for future enhancement.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-17 06:00:26 -07:00

159 lines
4.5 KiB
Python

"""
Example: Import credentials from a client project directory.
This script demonstrates a real-world use case for the credential scanner:
importing credentials from a client's project directory into the ClaudeTools
credential vault with automatic encryption.
Usage:
python example_credential_import.py /path/to/client/project [--client-id UUID]
"""
import argparse
import logging
import sys
from pathlib import Path
from api.database import SessionLocal
from api.utils.credential_scanner import (
scan_for_credential_files,
parse_credential_file,
import_credentials_to_db,
scan_and_import_credentials,
)
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
def preview_credentials(base_path: str):
"""Preview credentials that would be imported without actually importing."""
logger.info(f"Scanning for credentials in: {base_path}")
# Find credential files
files = scan_for_credential_files(base_path)
if not files:
logger.warning("No credential files found")
return []
logger.info(f"\nFound {len(files)} credential file(s):")
for file_path in files:
logger.info(f" - {file_path}")
# Parse and preview
all_credentials = []
for file_path in files:
credentials = parse_credential_file(file_path)
all_credentials.extend(credentials)
logger.info(f"\n{Path(file_path).name}:")
for cred in credentials:
logger.info(f" Service: {cred.get('service_name')}")
logger.info(f" Type: {cred.get('credential_type')}")
if cred.get('username'):
logger.info(f" Username: {cred.get('username')}")
logger.info("")
logger.info(f"Total credentials found: {len(all_credentials)}")
return all_credentials
def import_with_confirmation(base_path: str, client_id: str = None):
"""Import credentials with user confirmation."""
# Preview first
credentials = preview_credentials(base_path)
if not credentials:
logger.info("No credentials to import")
return
# Ask for confirmation
logger.info("\n" + "=" * 60)
response = input(f"Import {len(credentials)} credential(s) to database? (yes/no): ")
if response.lower() not in ['yes', 'y']:
logger.info("Import cancelled")
return
# Import to database
db = SessionLocal()
try:
logger.info("\nImporting credentials...")
results = scan_and_import_credentials(
base_path=base_path,
db=db,
client_id=client_id,
user_id="manual_import",
ip_address=None
)
logger.info("\n" + "=" * 60)
logger.info("IMPORT COMPLETE")
logger.info("=" * 60)
logger.info(f"Files scanned: {results['files_found']}")
logger.info(f"Credentials parsed: {results['credentials_parsed']}")
logger.info(f"Credentials imported: {results['credentials_imported']}")
if results['credentials_imported'] < results['credentials_parsed']:
logger.warning(
f"Warning: {results['credentials_parsed'] - results['credentials_imported']} "
"credential(s) failed to import. Check logs for details."
)
except Exception as e:
logger.error(f"Import failed: {str(e)}", exc_info=True)
raise
finally:
db.close()
def main():
"""Main entry point."""
parser = argparse.ArgumentParser(
description="Import credentials from a directory into ClaudeTools credential vault"
)
parser.add_argument(
'path',
type=str,
help='Path to directory containing credential files'
)
parser.add_argument(
'--client-id',
type=str,
help='UUID of client to associate credentials with (optional)',
default=None
)
parser.add_argument(
'--preview',
action='store_true',
help='Preview credentials without importing'
)
args = parser.parse_args()
# Validate path
path = Path(args.path)
if not path.exists():
logger.error(f"Path does not exist: {args.path}")
sys.exit(1)
if not path.is_dir():
logger.error(f"Path is not a directory: {args.path}")
sys.exit(1)
# Preview or import
if args.preview:
preview_credentials(str(path))
else:
import_with_confirmation(str(path), args.client_id)
if __name__ == "__main__":
main()