Files
claudetools/scripts/example_credential_import.py
Mike Swanson 06f7617718 feat: Major directory reorganization and cleanup
Reorganized project structure for better maintainability and reduced
disk usage by 95.9% (11 GB -> 451 MB).

Directory Reorganization (85% reduction in root files):
- Created docs/ with subdirectories (deployment, testing, database, etc.)
- Created infrastructure/vpn-configs/ for VPN scripts
- Moved 90+ files from root to organized locations
- Archived obsolete documentation (context system, offline mode, zombie debugging)
- Moved all test files to tests/ directory
- Root directory: 119 files -> 18 files

Disk Cleanup (10.55 GB recovered):
- Deleted Rust build artifacts: 9.6 GB (target/ directories)
- Deleted Python virtual environments: 161 MB (venv/ directories)
- Deleted Python cache: 50 KB (__pycache__/)

New Structure:
- docs/ - All documentation organized by category
- docs/archives/ - Obsolete but preserved documentation
- infrastructure/ - VPN configs and SSH setup
- tests/ - All test files consolidated
- logs/ - Ready for future logs

Benefits:
- Cleaner root directory (18 vs 119 files)
- Logical organization of documentation
- 95.9% disk space reduction
- Faster navigation and discovery
- Better portability (build artifacts excluded)

Build artifacts can be regenerated:
- Rust: cargo build --release (5-15 min per project)
- Python: pip install -r requirements.txt (2-3 min)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-18 20:42:28 -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()