security: remove hardcoded credentials and externalize user profiles
- DATABASE_URL now fails fast if not set (no default with password) - User profiles loaded from JSON config (config/user_profiles.json) - Add .env.example as template for environment variables - Add config/user_profiles.json.example as template for user configuration - Update .gitignore to exclude sensitive config files
This commit is contained in:
parent
c3931d78b1
commit
d27421a267
|
|
@ -0,0 +1,23 @@
|
||||||
|
# AI Station - Environment Variables Template
|
||||||
|
# Copy this file to .env and fill in your values
|
||||||
|
# IMPORTANT: Never commit .env to version control!
|
||||||
|
|
||||||
|
# === GOOGLE OAUTH ===
|
||||||
|
OAUTH_GOOGLE_CLIENT_ID=your_client_id_here
|
||||||
|
OAUTH_GOOGLE_CLIENT_SECRET=your_client_secret_here
|
||||||
|
|
||||||
|
# === CHAINLIT CONFIGURATION ===
|
||||||
|
CHAINLIT_URL=https://ai.dffm.it
|
||||||
|
CHAINLIT_AUTH_SECRET=generate_a_secure_random_string_here
|
||||||
|
|
||||||
|
# === DATABASE ===
|
||||||
|
# Format: postgresql+asyncpg://username:password@hostname:port/database_name
|
||||||
|
DATABASE_URL=postgresql+asyncpg://ai_user:your_secure_password@postgres:5432/ai_station
|
||||||
|
|
||||||
|
# === AI SERVICES ===
|
||||||
|
OLLAMA_URL=http://192.168.1.243:11434
|
||||||
|
QDRANT_URL=http://qdrant:6333
|
||||||
|
BGE_API_URL=http://192.168.1.243:8001/embed
|
||||||
|
|
||||||
|
# === OPTIONAL ===
|
||||||
|
# GEMINI_API_KEY=your_gemini_api_key_here
|
||||||
|
|
@ -7,3 +7,4 @@ qdrant_storage/.files/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
.env
|
.env
|
||||||
.files/
|
.files/
|
||||||
|
config/user_profiles.json
|
||||||
74
app.py
74
app.py
|
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
import shutil
|
import shutil
|
||||||
import requests
|
import requests
|
||||||
|
|
@ -37,10 +38,15 @@ except ImportError:
|
||||||
# =========================
|
# =========================
|
||||||
# CONFIG
|
# CONFIG
|
||||||
# =========================
|
# =========================
|
||||||
DATABASE_URL = os.getenv(
|
# SECURITY: Fail fast if DATABASE_URL is not set
|
||||||
"DATABASE_URL",
|
DATABASE_URL = os.getenv("DATABASE_URL")
|
||||||
"postgresql+asyncpg://ai_user:secure_password_here@postgres:5432/ai_station",
|
if not DATABASE_URL:
|
||||||
)
|
raise EnvironmentError(
|
||||||
|
"DATABASE_URL environment variable is required. "
|
||||||
|
"Set it via: export DATABASE_URL='postgresql+asyncpg://user:pass@host:5432/db'"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Service URLs - can be overridden via environment
|
||||||
OLLAMA_URL = os.getenv("OLLAMA_URL", "http://192.168.1.243:11434")
|
OLLAMA_URL = os.getenv("OLLAMA_URL", "http://192.168.1.243:11434")
|
||||||
QDRANT_URL = os.getenv("QDRANT_URL", "http://qdrant:6333")
|
QDRANT_URL = os.getenv("QDRANT_URL", "http://qdrant:6333")
|
||||||
BGE_API_URL = os.getenv("BGE_API_URL", "http://192.168.1.243:8001/embed")
|
BGE_API_URL = os.getenv("BGE_API_URL", "http://192.168.1.243:8001/embed")
|
||||||
|
|
@ -64,50 +70,24 @@ os.makedirs(STORAGE_DIR, exist_ok=True)
|
||||||
os.makedirs(WORKSPACES_DIR, exist_ok=True)
|
os.makedirs(WORKSPACES_DIR, exist_ok=True)
|
||||||
|
|
||||||
# =========================
|
# =========================
|
||||||
# USER PROFILES
|
# USER PROFILES (loaded from JSON for security)
|
||||||
# =========================
|
# =========================
|
||||||
USER_PROFILES = {
|
def load_user_profiles() -> Dict[str, Dict]:
|
||||||
"giuseppe@defranceschi.pro": {
|
"""Load user profiles from JSON config file."""
|
||||||
"role": "admin",
|
config_path = os.getenv("USER_PROFILES_PATH", "config/user_profiles.json")
|
||||||
"name": "Giuseppe",
|
try:
|
||||||
"workspace": "admin_workspace",
|
with open(config_path, "r", encoding="utf-8") as f:
|
||||||
"rag_collection": "admin_docs",
|
config = json.load(f)
|
||||||
"capabilities": ["debug", "all"],
|
return config.get("user_profiles", {})
|
||||||
"show_code": True,
|
except FileNotFoundError:
|
||||||
},
|
print(f"WARNING: User profiles config not found at {config_path}")
|
||||||
"federica.tecchio@gmail.com": {
|
return {}
|
||||||
"role": "business",
|
except json.JSONDecodeError as e:
|
||||||
"name": "Federica",
|
print(f"WARNING: Invalid JSON in user profiles config: {e}")
|
||||||
"workspace": "business_workspace",
|
return {}
|
||||||
"rag_collection": "contabilita",
|
|
||||||
"capabilities": ["basic_chat"],
|
# Load profiles at startup
|
||||||
"show_code": False,
|
USER_PROFILES = load_user_profiles()
|
||||||
},
|
|
||||||
"riccardob545@gmail.com": {
|
|
||||||
"role": "engineering",
|
|
||||||
"name": "Riccardo",
|
|
||||||
"workspace": "engineering_workspace",
|
|
||||||
"rag_collection": "engineering_docs",
|
|
||||||
"capabilities": ["code"],
|
|
||||||
"show_code": True,
|
|
||||||
},
|
|
||||||
"giuliadefranceschi05@gmail.com": {
|
|
||||||
"role": "architecture",
|
|
||||||
"name": "Giulia",
|
|
||||||
"workspace": "architecture_workspace",
|
|
||||||
"rag_collection": "architecture_manuals",
|
|
||||||
"capabilities": ["visual"],
|
|
||||||
"show_code": False,
|
|
||||||
},
|
|
||||||
"giuseppe.defranceschi@gmail.com": {
|
|
||||||
"role": "architecture",
|
|
||||||
"name": "Giuseppe",
|
|
||||||
"workspace": "architecture_workspace",
|
|
||||||
"rag_collection": "architecture_manuals",
|
|
||||||
"capabilities": ["visual"],
|
|
||||||
"show_code": False,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
GUEST_PROFILE = {
|
GUEST_PROFILE = {
|
||||||
"role": "guest",
|
"role": "guest",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
{
|
||||||
|
"user_profiles": {
|
||||||
|
"giuseppe@defranceschi.pro": {
|
||||||
|
"role": "admin",
|
||||||
|
"name": "Giuseppe",
|
||||||
|
"workspace": "admin_workspace",
|
||||||
|
"rag_collection": "admin_docs",
|
||||||
|
"capabilities": ["debug", "all"],
|
||||||
|
"show_code": true
|
||||||
|
},
|
||||||
|
"federica.tecchio@gmail.com": {
|
||||||
|
"role": "business",
|
||||||
|
"name": "Federica",
|
||||||
|
"workspace": "business_workspace",
|
||||||
|
"rag_collection": "contabilita",
|
||||||
|
"capabilities": ["basic_chat"],
|
||||||
|
"show_code": false
|
||||||
|
},
|
||||||
|
"riccardob545@gmail.com": {
|
||||||
|
"role": "engineering",
|
||||||
|
"name": "Riccardo",
|
||||||
|
"workspace": "engineering_workspace",
|
||||||
|
"rag_collection": "engineering_docs",
|
||||||
|
"capabilities": ["code"],
|
||||||
|
"show_code": true
|
||||||
|
},
|
||||||
|
"giuliadefranceschi05@gmail.com": {
|
||||||
|
"role": "architecture",
|
||||||
|
"name": "Giulia",
|
||||||
|
"workspace": "architecture_workspace",
|
||||||
|
"rag_collection": "architecture_manuals",
|
||||||
|
"capabilities": ["visual"],
|
||||||
|
"show_code": false
|
||||||
|
},
|
||||||
|
"giuseppe.defranceschi@gmail.com": {
|
||||||
|
"role": "architecture",
|
||||||
|
"name": "Giuseppe",
|
||||||
|
"workspace": "architecture_workspace",
|
||||||
|
"rag_collection": "architecture_manuals",
|
||||||
|
"capabilities": ["visual"],
|
||||||
|
"show_code": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"guest_profile": {
|
||||||
|
"role": "guest",
|
||||||
|
"name": "Guest",
|
||||||
|
"workspace": "guest",
|
||||||
|
"rag_collection": "public",
|
||||||
|
"capabilities": ["basic_chat"],
|
||||||
|
"show_code": false
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue