feat: implement deployment isolation verification and enhance API URL patching

This commit is contained in:
WhiteX 2025-06-12 18:37:53 +03:00 committed by rzmk
parent e10e8ee5ba
commit 482dd930ce
4 changed files with 143 additions and 10 deletions

View file

@ -47,14 +47,20 @@ See `COOLIFY_ENV_VARS.md` for complete list. Key variables for isolation:
- ✅ **Port mismatch fixed**: Changed from 3000 to 80
- ✅ **Container accessibility**: Traefik can now route to port 80
- ✅ **Frontend running**: Next.js server operational on port 8000
- ❌ **Backend failing**: PM2 bash execution error fixed
- ⚠️ **502 errors**: Should resolve once backend starts correctly
- ✅ **Backend running**: FastAPI server operational on port 9000
- ❌ **Cross-deployment contamination**: LIVE calling DEV APIs and vice versa
- ⚠️ **Root cause**: Frontend build-time API URLs not properly isolated
### Identified Issues & Fixes:
**Problem**: Backend API service failing with bash execution error
**Root Cause**: Incorrect PM2 command syntax for starting uvicorn
**Solution**: Updated start script to use direct Python execution instead of bash interpreter
**Problem**: Cross-deployment data contamination (LIVE sees DEV data)
**Root Cause**: Next.js build embeds API URLs at build-time, both deployments may share same URLs
**Solution**: Added runtime API URL patching in Docker container startup
**Current Fix Applied**:
1. ✅ Enhanced patched-start.sh to replace API URLs at runtime
2. ✅ Added debug endpoint `/api/v1/debug/deployment` for verification
3. ✅ Added deployment verification script `verify-isolation.sh`
### Next Debugging Steps:
@ -102,14 +108,25 @@ The 502 errors should resolve once:
### Post-Deploy Verification:
After redeploying, run the debug script again and verify:
After redeploying, verify isolation works:
```bash
docker exec -it <container_name> /app/debug-services.sh
# Run the automated verification script
./verify-isolation.sh
# Or manually test the debug endpoints
curl https://adr-lms.whitex.cloud/api/v1/debug/deployment
curl https://edu.adradviser.ro/api/v1/debug/deployment
# Check for cross-deployment API calls in browser Network tab
# Should see only same-domain API calls:
# - DEV: Only calls to adr-lms.whitex.cloud
# - LIVE: Only calls to edu.adradviser.ro
```
Expected output should show:
- ✅ PM2 status: Both services "online"
- ✅ Port 9000: Backend responding with status 200
- ✅ No bash execution errors in logs
- ✅ Different database hosts for DEV vs LIVE
- ✅ Different cookie domains: adr-lms.whitex.cloud vs edu.adradviser.ro
- ✅ No cross-domain API calls in browser Network tab
- ✅ Separate content/courses on each deployment
The port configuration fix was the critical missing piece for Traefik routing.

View file

@ -69,6 +69,12 @@ find /app/web/.next -type f -name "*.js" -exec sed -i "s/domain:[^,}]*,/domain:
find /app/web/.next -type f -name "*.js" -exec sed -i "s/domain: *process.env.LEARNHOUSE_COOKIE_DOMAIN/domain: undefined/g" {} \\;\n\
find /app/web/.next -type f -name "*.js" -exec sed -i "s/\.domain\s*=\s*[^;]*;/\.domain = undefined;/g" {} \\;\n\
echo "Patch complete."\n\
echo "Patching API URLs for deployment isolation..."\n\
if [ ! -z "$NEXT_PUBLIC_LEARNHOUSE_API_URL" ]; then\n\
find /app/web/.next -type f -name "*.js" -exec sed -i "s|https://[^/\"]*\\(/api/v1/\\)|${NEXT_PUBLIC_LEARNHOUSE_API_URL}|g" {} \\;\n\
find /app/web/.next -type f -name "*.js" -exec sed -i "s|https://[^/\"]*\\(/api/auth\\)|${NEXT_PUBLIC_LEARNHOUSE_BACKEND_URL}api/auth|g" {} \\;\n\
echo "API URLs patched to: $NEXT_PUBLIC_LEARNHOUSE_API_URL"\n\
fi\n\
sh /app/start.sh' > /app/patched-start.sh && chmod +x /app/patched-start.sh
# Use the patched start script

View file

@ -1,4 +1,5 @@
import uvicorn
import os
# import logfire
from fastapi import FastAPI, Request
from config.config import LearnHouseConfig, get_learnhouse_config
@ -20,6 +21,15 @@ from fastapi.middleware.gzip import GZipMiddleware
# Get LearnHouse Config
learnhouse_config: LearnHouseConfig = get_learnhouse_config()
# Debug logging for deployment isolation
print(f"🔍 DEPLOYMENT DEBUG INFO:")
print(f" DEPLOYMENT_NAME: {os.environ.get('DEPLOYMENT_NAME', 'NOT_SET')}")
print(f" DATABASE: {learnhouse_config.database_config.sql_connection_string[:50]}...")
print(f" REDIS: {learnhouse_config.redis_config.redis_connection_string[:50]}...")
print(f" COOKIE_DOMAIN: {learnhouse_config.hosting_config.cookie_config.domain}")
print(f" API_DOMAIN: {learnhouse_config.hosting_config.domain}")
print(f"🔍 END DEBUG INFO")
# Global Config
app = FastAPI(
title=learnhouse_config.site_name,
@ -83,3 +93,15 @@ if __name__ == "__main__":
@app.get("/")
async def root():
return {"Message": "Welcome to LearnHouse ✨"}
# Debug endpoint for deployment verification
@app.get("/debug/deployment")
async def debug_deployment():
import os
return {
"deployment_name": os.environ.get('DEPLOYMENT_NAME', 'NOT_SET'),
"cookie_domain": learnhouse_config.hosting_config.cookie_config.domain,
"api_domain": learnhouse_config.hosting_config.domain,
"database_host": learnhouse_config.database_config.sql_connection_string.split('@')[1].split('/')[0] if '@' in learnhouse_config.database_config.sql_connection_string else "unknown",
"redis_host": learnhouse_config.redis_config.redis_connection_string.split('@')[1].split(':')[0] if '@' in learnhouse_config.redis_config.redis_connection_string else "unknown"
}

88
verify-isolation.sh Executable file
View file

@ -0,0 +1,88 @@
#!/bin/bash
echo "🔍 LearnHouse Deployment Isolation Verification"
echo "==============================================="
# Check DEV deployment
echo ""
echo "📋 DEV Deployment (adr-lms.whitex.cloud):"
echo "----------------------------------------"
echo "Testing API connection..."
DEV_RESPONSE=$(curl -s https://adr-lms.whitex.cloud/api/v1/debug/deployment 2>/dev/null)
if [ $? -eq 0 ]; then
echo "✅ DEV API accessible"
echo " Response: $DEV_RESPONSE"
else
echo "❌ DEV API not accessible"
fi
echo ""
echo "Testing frontend..."
DEV_FRONTEND=$(curl -s -o /dev/null -w "%{http_code}" https://adr-lms.whitex.cloud/ 2>/dev/null)
if [ "$DEV_FRONTEND" = "200" ]; then
echo "✅ DEV Frontend accessible (HTTP $DEV_FRONTEND)"
else
echo "❌ DEV Frontend issue (HTTP $DEV_FRONTEND)"
fi
# Check LIVE deployment
echo ""
echo "📋 LIVE Deployment (edu.adradviser.ro):"
echo "---------------------------------------"
echo "Testing API connection..."
LIVE_RESPONSE=$(curl -s https://edu.adradviser.ro/api/v1/debug/deployment 2>/dev/null)
if [ $? -eq 0 ]; then
echo "✅ LIVE API accessible"
echo " Response: $LIVE_RESPONSE"
else
echo "❌ LIVE API not accessible"
fi
echo ""
echo "Testing frontend..."
LIVE_FRONTEND=$(curl -s -o /dev/null -w "%{http_code}" https://edu.adradviser.ro/ 2>/dev/null)
if [ "$LIVE_FRONTEND" = "200" ]; then
echo "✅ LIVE Frontend accessible (HTTP $LIVE_FRONTEND)"
else
echo "❌ LIVE Frontend issue (HTTP $LIVE_FRONTEND)"
fi
# Analysis
echo ""
echo "🔍 Cross-Deployment Isolation Analysis:"
echo "========================================"
# Extract database hosts if responses are valid JSON
if command -v jq >/dev/null 2>&1; then
DEV_DB=$(echo "$DEV_RESPONSE" | jq -r '.database_host // "unknown"' 2>/dev/null)
LIVE_DB=$(echo "$LIVE_RESPONSE" | jq -r '.database_host // "unknown"' 2>/dev/null)
if [ "$DEV_DB" != "unknown" ] && [ "$LIVE_DB" != "unknown" ]; then
if [ "$DEV_DB" = "$LIVE_DB" ]; then
echo "⚠️ WARNING: Both deployments using same database host: $DEV_DB"
else
echo "✅ Database isolation: DEV($DEV_DB) ≠ LIVE($LIVE_DB)"
fi
fi
DEV_COOKIE=$(echo "$DEV_RESPONSE" | jq -r '.cookie_domain // "unknown"' 2>/dev/null)
LIVE_COOKIE=$(echo "$LIVE_RESPONSE" | jq -r '.cookie_domain // "unknown"' 2>/dev/null)
if [ "$DEV_COOKIE" != "unknown" ] && [ "$LIVE_COOKIE" != "unknown" ]; then
if [ "$DEV_COOKIE" = "$LIVE_COOKIE" ]; then
echo "⚠️ WARNING: Both deployments using same cookie domain: $DEV_COOKIE"
else
echo "✅ Cookie isolation: DEV($DEV_COOKIE) ≠ LIVE($LIVE_COOKIE)"
fi
fi
else
echo " Install 'jq' for detailed analysis"
fi
echo ""
echo "🚀 Next Steps:"
echo "=============="
echo "1. If APIs are accessible, check browser Network tab for cross-deployment calls"
echo "2. Clear browser cache/cookies for both domains"
echo "3. Test in incognito mode to verify isolation"
echo "4. Check container logs: docker logs <container_name>"