File size: 4,842 Bytes
9846bab
 
f899610
9846bab
 
 
 
f899610
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9846bab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f899610
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9846bab
 
 
 
 
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
174
175
176
"""
Configuration management for ARF Demo
Updated for Pydantic v2 with pydantic-settings
"""
from typing import Optional, Dict, Any, List
from enum import Enum
import os
import logging

logger = logging.getLogger(__name__)

# Try to import from pydantic-settings, fallback to pydantic
try:
    from pydantic_settings import BaseSettings
    from pydantic import Field, validator
    PYDANTIC_V2 = True
    logger.info("Using pydantic-settings for BaseSettings")
except ImportError:
    try:
        from pydantic import BaseSettings, Field, validator
        PYDANTIC_V2 = False
        logger.info("Using pydantic.BaseSettings (older version)")
    except ImportError as e:
        logger.error(f"Failed to import pydantic: {e}")
        # Create minimal fallback
        class BaseSettings:
            def __init__(self, **kwargs):
                for k, v in kwargs.items():
                    setattr(self, k, v)
        
        class Field:
            @staticmethod
            def default(value):
                return value
        
        def validator(*args, **kwargs):
            def decorator(func):
                return func
            return decorator
        
        PYDANTIC_V2 = False


class ARFMode(str, Enum):
    """ARF operation modes"""
    DEMO = "demo"
    OSS = "oss"
    ENTERPRISE = "enterprise"


class SafetyMode(str, Enum):
    """Safety modes for execution"""
    ADVISORY = "advisory"
    APPROVAL = "approval"
    AUTONOMOUS = "autonomous"


class Settings(BaseSettings):
    """
    Application settings with environment variable support
    """
    
    # ===== System Mode =====
    arf_mode: ARFMode = Field(
        default=ARFMode.DEMO,
        description="ARF operation mode"
    )
    
    use_mock_arf: bool = Field(
        default=True,
        description="Use mock ARF implementation (for demo mode)"
    )
    
    # ===== ARF Configuration =====
    arf_api_key: Optional[str] = Field(
        default=None,
        description="ARF API key for real integration"
    )
    
    arf_base_url: str = Field(
        default="https://api.arf.dev",
        description="ARF API base URL"
    )
    
    # ===== Business Configuration =====
    engineer_hourly_rate: float = Field(
        default=150.0,
        description="Engineer hourly rate in USD"
    )
    
    engineer_annual_cost: float = Field(
        default=125000.0,
        description="Engineer annual cost in USD"
    )
    
    default_savings_rate: float = Field(
        default=0.82,
        description="Default savings rate with ARF"
    )
    
    # ===== UI Configuration =====
    auto_refresh_seconds: int = Field(
        default=30,
        description="Auto-refresh interval in seconds"
    )
    
    max_history_items: int = Field(
        default=100,
        description="Maximum history items to display"
    )
    
    # ===== Demo Configuration =====
    default_scenario: str = Field(
        default="Cache Miss Storm",
        description="Default incident scenario"
    )
    
    scenario_config_path: str = Field(
        default="config/scenarios",
        description="Path to scenario configuration files"
    )
    
    # ===== Safety Configuration =====
    default_safety_mode: SafetyMode = Field(
        default=SafetyMode.ADVISORY,
        description="Default safety mode"
    )
    
    require_approval: bool = Field(
        default=True,
        description="Require human approval for execution"
    )
    
    # ===== Validation =====
    @validator("arf_api_key")
    def validate_api_key(cls, v: Optional[str], values: Dict[str, Any]) -> Optional[str]:
        if values.get("arf_mode") == ARFMode.ENTERPRISE and not v:
            raise ValueError("ARF API key required for Enterprise mode")
        return v
    
    @validator("use_mock_arf")
    def validate_mock_mode(cls, v: bool, values: Dict[str, Any]) -> bool:
        if values.get("arf_mode") == ARFMode.DEMO:
            return True
        return v
    
    class Config:
        env_file = ".env"
        env_file_encoding = "utf-8"
        case_sensitive = False
        use_enum_values = True


# Global settings instance with fallback
try:
    settings = Settings()
except Exception as e:
    logger.warning(f"Failed to load settings from .env: {e}, using defaults")
    settings = Settings(
        arf_mode=ARFMode.DEMO,
        use_mock_arf=True,
        engineer_hourly_rate=150.0,
        engineer_annual_cost=125000.0,
        default_savings_rate=0.82,
        auto_refresh_seconds=30,
        max_history_items=100,
        default_scenario="Cache Miss Storm",
        scenario_config_path="config/scenarios",
        default_safety_mode=SafetyMode.ADVISORY,
        require_approval=True
    )


def get_settings() -> Settings:
    """Get settings instance (singleton pattern)"""
    return settings