Skip to content

Commit f0087bc

Browse files
committed
Add credential management and inference testing system
- Added CredentialManager for persistent credential storage in .credentials.env.json - Added inference_test.py for actual model inference testing (replaces health checks) - Added ModelCatalogManager to manage model catalog in model_catalog.json - Replaced CustomEndpointManager with integrated ModelCatalogManager - Changed GOOGLE_API_KEY to GEMINI_API_KEY for consistency with project metadata - Updated /test_model_endpoint to perform real inference with small prompt - Added /set_credentials and /credentials/status endpoints - Updated .gitignore to exclude sensitive credentials and dynamic catalog files - All credentials now managed via environment variables with persistence - Endpoint URLs for CAII and OpenAI compatible must come from client
1 parent 4c23343 commit f0087bc

File tree

10 files changed

+884
-593
lines changed

10 files changed

+884
-593
lines changed

.gitignore

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,11 @@ SeedsInstructions.json
6565
nm.json
6666
french_input.json
6767

68-
# Custom endpoint configurations (contains sensitive credentials)
69-
custom_model_endpoints.json
68+
# Credential storage file (contains sensitive credentials)
69+
.credentials.env.json
70+
71+
# Model catalog (dynamically generated, environment-specific)
72+
model_catalog.json
7073

7174
# DB
7275
*metadata.db-shm

.project-metadata.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ environment_variables:
1818
default: null
1919
description: >-
2020
AWS Secret Key
21-
AWS_DEFAULT_REGION:
21+
AWS_REGION:
2222
default: "us-east-1"
2323
description: >-
2424
AWS region

app/core/credential_manager.py

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import json
2+
import os
3+
from pathlib import Path
4+
from typing import Dict, Optional, List
5+
6+
7+
class CredentialManager:
8+
"""
9+
Manages persistent credentials across app restarts.
10+
11+
Credentials are stored in .credentials.env.json and loaded into os.environ
12+
at startup. This allows credentials to persist across restarts while keeping
13+
them separate from endpoint metadata.
14+
"""
15+
16+
CREDENTIAL_FILE = Path(".credentials.env.json")
17+
18+
# List of credential keys we manage
19+
CREDENTIAL_KEYS = [
20+
"CDP_TOKEN",
21+
"OPENAI_API_KEY",
22+
"GEMINI_API_KEY",
23+
"OpenAI_Endpoint_Compatible_Key",
24+
"AWS_ACCESS_KEY_ID",
25+
"AWS_SECRET_ACCESS_KEY",
26+
"AWS_REGION"
27+
]
28+
29+
@classmethod
30+
def initialize(cls):
31+
"""
32+
Initialize credentials at app startup.
33+
34+
If .credentials.env.json exists: Load credentials from file
35+
If it doesn't exist: Create it from current environment variables
36+
"""
37+
if cls.CREDENTIAL_FILE.exists():
38+
print(f"📂 Loading persisted credentials from {cls.CREDENTIAL_FILE}")
39+
cls._load_from_file()
40+
else:
41+
print(f"🆕 First boot: Creating {cls.CREDENTIAL_FILE} from environment variables")
42+
cls._create_from_environment()
43+
44+
@classmethod
45+
def _load_from_file(cls):
46+
"""Load credentials from file into os.environ"""
47+
try:
48+
with open(cls.CREDENTIAL_FILE) as f:
49+
credentials = json.load(f)
50+
51+
loaded_count = 0
52+
53+
for key, value in credentials.items():
54+
if value: # Only set non-empty values
55+
os.environ[key] = value
56+
loaded_count += 1
57+
58+
print(f"Loaded {loaded_count} credentials into environment")
59+
60+
except json.JSONDecodeError as e:
61+
print(f" Warning: Failed to parse {cls.CREDENTIAL_FILE}: {e}")
62+
except Exception as e:
63+
print(f"Warning: Failed to load credentials: {e}")
64+
65+
@classmethod
66+
def _create_from_environment(cls):
67+
"""Create credential file from current environment variables"""
68+
try:
69+
# Extract existing values from environment
70+
initial_creds = {}
71+
for key in cls.CREDENTIAL_KEYS:
72+
if value := os.getenv(key):
73+
initial_creds[key] = value
74+
75+
# Create the file with initial credentials
76+
with open(cls.CREDENTIAL_FILE, 'w') as f:
77+
json.dump(initial_creds, f, indent=2)
78+
79+
print(f"✅ Created {cls.CREDENTIAL_FILE} with {len(initial_creds)} credentials from environment")
80+
81+
except Exception as e:
82+
print(f"⚠️ Warning: Failed to create credential file: {e}")
83+
84+
@classmethod
85+
def set_credentials(cls, credentials: Dict[str, str]) -> Dict[str, int]:
86+
"""
87+
Set one or more credentials - updates both memory and file.
88+
89+
Args:
90+
credentials: Dictionary of credential key-value pairs
91+
92+
Returns:
93+
Dictionary with count of updated and new credentials
94+
"""
95+
# Load existing credentials
96+
if cls.CREDENTIAL_FILE.exists():
97+
with open(cls.CREDENTIAL_FILE) as f:
98+
existing_creds = json.load(f)
99+
else:
100+
existing_creds = {}
101+
102+
# Track updates
103+
updated_count = 0
104+
new_count = 0
105+
106+
for key, value in credentials.items():
107+
# Update memory (immediate effect)
108+
os.environ[key] = value
109+
110+
# Update file
111+
if key in existing_creds:
112+
updated_count += 1
113+
else:
114+
new_count += 1
115+
116+
existing_creds[key] = value
117+
118+
# Save updated credentials
119+
with open(cls.CREDENTIAL_FILE, 'w') as f:
120+
json.dump(existing_creds, f, indent=2)
121+
122+
return {"updated": updated_count, "new": new_count}
123+
124+
@classmethod
125+
def get_credential(cls, key: str) -> Optional[str]:
126+
"""
127+
Get a credential from environment.
128+
129+
Args:
130+
key: Credential key
131+
132+
Returns:
133+
Credential value or None if not found
134+
"""
135+
return os.getenv(key)
136+
137+
@classmethod
138+
def list_available_credentials(cls) -> List[Dict[str, bool]]:
139+
"""
140+
List all credential keys and whether they are set.
141+
142+
Returns:
143+
List of dictionaries with key and is_set status
144+
"""
145+
return [
146+
{
147+
"key": key,
148+
"is_set": bool(os.getenv(key))
149+
}
150+
for key in cls.CREDENTIAL_KEYS
151+
]
152+

0 commit comments

Comments
 (0)