File size: 5,255 Bytes
4a2ab42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4ae946d
 
 
4a2ab42
4ae946d
 
 
4a2ab42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#!/usr/bin/env python3
"""
Environment Configuration Validator

Validates that all required environment variables are set and properly formatted
for the Zenith Fraud Detection Platform.
"""

import base64
import os
import sys
from typing import List, Tuple


def validate_fernet_key(key: str, name: str) -> bool:
    """Validate that a key is a proper Fernet key (32 bytes, base64 encoded)"""
    try:
        # Fernet keys must be 32 bytes when decoded
        decoded = base64.urlsafe_b64decode(key)
        if len(decoded) != 32:
            print(f"❌ {name}: Invalid key length ({len(decoded)} bytes, must be 32)")
            return False
        return True
    except Exception as e:
        print(f"❌ {name}: Invalid base64 encoding - {e}")
        return False


def validate_environment_variables() -> Tuple[List[str], List[str]]:
    """Validate all required environment variables"""
    missing = []
    invalid = []

    # Required variables
    required_vars = {
        "SECRET_KEY": "General application secret key",
        "FIELD_ENCRYPTION_KEY": "Database field encryption key (Fernet)",
    }

    # Optional but recommended
    optional_vars = {
        "ENCRYPTION_KEY": "Alternative encryption key (Fernet)",
        "DATABASE_URL": "Database connection URL",
        "REDIS_URL": "Redis connection URL",
        "LOG_LEVEL": "Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)",
        "ENVIRONMENT": "Application environment (development, staging, production)",
    }

    # Check required variables
    for var, description in required_vars.items():
        value = os.getenv(var)
        if not value:
            missing.append(f"{var} - {description}")
        elif var.endswith("_ENCRYPTION_KEY"):
            if not validate_fernet_key(value, var):
                invalid.append(var)

    # Check optional variables
    for var, description in optional_vars.items():
        value = os.getenv(var)
        if value and var.endswith("_ENCRYPTION_KEY"):
            if not validate_fernet_key(value, var):
                invalid.append(var)

    return missing, invalid


def validate_database_connection() -> bool:
    """Test database connection if DATABASE_URL is set"""
    db_url = os.getenv("DATABASE_URL")
    if not db_url:
        print("⚠️  DATABASE_URL not set - skipping database connection test")
        return True

    try:
        if db_url.startswith("sqlite"):
            # SQLite - just check if path is accessible
            if db_url == "sqlite:///:memory:":
                print("βœ… DATABASE_URL set to in-memory SQLite (valid for testing)")
                return True

            import sqlite3

            # Extract path from sqlite:///path
            db_path = db_url.replace("sqlite:///", "")
            conn = sqlite3.connect(db_path)
            conn.close()
            print("βœ… SQLite database connection successful")
            return True
        else:
            # Other databases - just validate URL format
            print("βœ… DATABASE_URL format appears valid")
            return True
    except Exception as e:
        print(f"❌ Database connection test failed: {e}")
        return False


def validate_redis_connection() -> bool:
    """Test Redis connection if REDIS_URL is set"""
    redis_url = os.getenv("REDIS_URL")
    if not redis_url:
        print("⚠️  REDIS_URL not set - skipping Redis connection test")
        return True

    try:
        import redis

        r = redis.from_url(redis_url)
        r.ping()
        print("βœ… Redis connection successful")
        return True
    except ImportError:
        print("⚠️  redis package not installed - skipping Redis test")
        return True
    except Exception as e:
        print(f"❌ Redis connection test failed: {e}")
        return False


def main():
    """Main validation function"""
    print("πŸ” Zenith Platform Environment Configuration Validator")
    print("=" * 60)

    # Check Python version
    if sys.version_info < (3, 12):
        print(
            f"⚠️  Python {sys.version_info.major}.{sys.version_info.minor} detected. Python 3.12+ recommended."
        )
    else:
        print(
            f"βœ… Python {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro} detected"
        )

    print()

    # Validate environment variables
    missing, invalid = validate_environment_variables()

    if missing:
        print("❌ Missing required environment variables:")
        for var in missing:
            print(f"   β€’ {var}")
        print()

    if invalid:
        print("❌ Invalid environment variables:")
        for var in invalid:
            print(f"   β€’ {var}")
        print()

    # Test connections
    db_ok = validate_database_connection()
    redis_ok = validate_redis_connection()

    print()
    print("=" * 60)

    # Summary
    if not missing and not invalid and db_ok and redis_ok:
        print("βœ… Environment configuration is VALID")
        print("πŸš€ Ready for deployment")
        return 0
    else:
        print("❌ Environment configuration has ISSUES")
        print("πŸ”§ Please fix the issues above before deployment")
        return 1


if __name__ == "__main__":
    sys.exit(main())