Implement comprehensive deployment isolation fixes and verification tools

This commit is contained in:
WhiteX 2025-06-12 21:42:04 +03:00 committed by rzmk
parent 0a9d0df15d
commit e94fcded2a
7 changed files with 534 additions and 48 deletions

155
DATABASE_ISOLATION_FIX.md Normal file
View file

@ -0,0 +1,155 @@
# Database Isolation Fix for LearnHouse Deployments
## Issues Identified: Multiple Sources of Cross-Deployment Contamination
We have identified several issues causing cross-deployment contamination between DEV (adr-lms.whitex.cloud) and LIVE (edu.adradviser.ro) environments:
### 1. Shared Database Connection
Both deployments are connecting to the same database server, causing data sharing:
- DEV: `postgresql://learnhouse_dev:YOUR_DEV_DB_PASSWORD@db:5432/learnhouse_dev`
- LIVE: `postgresql://learnhouse:YOUR_LIVE_DB_PASSWORD@db:5432/learnhouse`
The container networking is not isolating these properly, causing both deployments to resolve `db` to the same physical database server.
### 2. Hardcoded URLs in Frontend Bundle
The DEV deployment contains hardcoded URLs pointing to the LIVE site:
- `http://edu.adradviser.ro/collections/new`
- `http://edu.adradviser.ro/courses?new=true`
These URLs are embedded in the JavaScript bundles at build time and aren't being properly updated at runtime.
### 3. Container API Access Inconsistencies
The API is accessed differently from inside containers versus from outside:
- Inside container: via `http://localhost:9000`
- External access: via domain's `/api/v1` path
This inconsistency complicates URL patching and can cause references to the wrong domain.
## How to Fix Deployment Isolation
### 1. Database Connection Isolation
Each deployment must use its own fully-qualified database hostname:
1. For DEV deployment:
```
LEARNHOUSE_SQL_CONNECTION_STRING=postgresql://learnhouse_dev:YOUR_DEV_DB_PASSWORD@db-dev.${DEPLOYMENT_NAME}-network:5432/learnhouse_dev
```
2. For LIVE deployment:
```
LEARNHOUSE_SQL_CONNECTION_STRING=postgresql://learnhouse:YOUR_LIVE_DB_PASSWORD@db-live.${DEPLOYMENT_NAME}-network:5432/learnhouse
```
This ensures:
- Each deployment uses a uniquely named database server
- The server hostname includes the deployment name for clarity
- The network name is deployment-specific
### 2. Enhanced URL Patching
We've improved the URL patching in Dockerfile_coolify to handle multiple URL formats:
```bash
# Replace all occurrences of edu.adradviser.ro with the current domain
find /app/web/.next -type f -name "*.js" -exec sed -i "s|http://edu.adradviser.ro|$NEXT_PUBLIC_LEARNHOUSE_DOMAIN|g" {} \;
find /app/web/.next -type f -name "*.js" -exec sed -i "s|https://edu.adradviser.ro|$NEXT_PUBLIC_LEARNHOUSE_DOMAIN|g" {} \;
find /app/web/.next -type f -name "*.js" -exec sed -i "s|//edu.adradviser.ro|//$DOMAIN_ONLY|g" {} \;
find /app/web/.next -type f -name "*.js" -exec sed -i "s|\"href\":\"http://edu.adradviser.ro|\"href\":\"$NEXT_PUBLIC_LEARNHOUSE_DOMAIN|g" {} \;
```
### 3. Cookie Domain Isolation
Ensure each deployment uses its own cookie domain:
```
LEARNHOUSE_COOKIE_DOMAIN=adr-lms.whitex.cloud # For DEV
LEARNHOUSE_COOKIE_DOMAIN=edu.adradviser.ro # For LIVE
```
### 4. API URL Inside vs Outside Container
Address the inconsistency in how the API is accessed:
1. Inside container: `http://localhost:9000`
2. External access: via domain's `/api/v1` path
Solution:
- Added the debug endpoint at `/api/v1/debug` to ensure it's accessible externally
- Enhanced the URL patching to handle both internal and external URL formats
### 5. API Debug Endpoints
Added comprehensive debug endpoints:
1. `/api/v1/debug/deployment` - Shows deployment configuration details
2. `/api/v1/debug/urls` - Scans for any remaining hardcoded URLs in the frontend bundle
## Verification Process
After implementing these fixes, use this verification process:
1. **Deploy the API changes** to add the debug endpoints:
```bash
git add apps/api/src/routers/debug.py apps/api/src/router.py apps/api/app.py
git commit -m "Add isolation debug endpoints for deployment verification"
git push
# Deploy through your CI/CD process
```
2. **Verify database isolation** by accessing the debug endpoints:
```bash
# Check DEV deployment
curl -k https://adr-lms.whitex.cloud/api/v1/debug/deployment
# Check LIVE deployment
curl -k https://edu.adradviser.ro/api/v1/debug/deployment
```
3. **Check for hardcoded URLs** in the frontend bundle:
```bash
# Check DEV deployment
curl -k https://adr-lms.whitex.cloud/api/v1/debug/urls
# Check LIVE deployment
curl -k https://edu.adradviser.ro/api/v1/debug/urls
```
4. **Test with incognito browsers** to ensure sessions don't cross-contaminate
5. **Run the verification script** to perform all checks automatically:
```bash
./verify-isolation.sh
```
Solution:
- Added the debug endpoint at `/api/v1/debug` to ensure it's accessible externally
- Enhanced the URL patching to handle both internal and external URL formats
### 5. API Debug Endpoints
Added comprehensive debug endpoints:
1. `/api/v1/debug/deployment` - Shows deployment configuration details
2. `/api/v1/debug/urls` - Scans for any remaining hardcoded URLs in the frontend bundle
4. **Network Isolation**: Updated docker-compose-coolify.yml to use deployment-specific networks.
## Verification Steps
After implementing these changes:
1. Run `./verify-isolation.sh` to check deployment isolation
2. Verify each deployment has its own database connection using `/api/v1/debug/deployment` endpoint
3. Check that no cross-domain references appear in the frontend
## Implementation Plan
1. Update database connection strings in Coolify environment variables for both deployments
2. Rebuild and redeploy both environments to apply the changes
3. Run the verification script to confirm isolation
4. Clear browser cookies and caches to test with clean state

View file

@ -62,19 +62,46 @@ COPY ./extra/start.sh /app/start.sh
COPY ./debug-services.sh /app/debug-services.sh
RUN chmod +x /app/start.sh /app/debug-services.sh
# Add near the end of your Dockerfile_coolify
# Add enhanced URL and domain patching
RUN echo '#!/bin/bash\n\
echo "Enhanced patching of NextAuth cookies..."\n\
echo "Enhanced patching of NextAuth cookies and domains..."\n\
find /app/web/.next -type f -name "*.js" -exec sed -i "s/domain:[^,}]*,/domain: undefined,/g" {} \\;\n\
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 "Cookie domain patches complete."\n\
\n\
echo "Patching API URLs for deployment isolation..."\n\
if [ ! -z "$NEXT_PUBLIC_LEARNHOUSE_API_URL" ]; then\n\
if [ ! -z "$NEXT_PUBLIC_LEARNHOUSE_DOMAIN" ]; then\n\
echo "Domain value found: $NEXT_PUBLIC_LEARNHOUSE_DOMAIN"\n\
# Extract the domain without protocol\n\
DOMAIN_ONLY=$(echo "$NEXT_PUBLIC_LEARNHOUSE_DOMAIN" | sed -E "s/^https?:\\/\\///g")\n\
echo "Extracted domain: $DOMAIN_ONLY"\n\
\n\
# Replace all occurrences of edu.adradviser.ro with the current domain\n\
find /app/web/.next -type f -name "*.js" -exec sed -i "s|http://edu.adradviser.ro|$NEXT_PUBLIC_LEARNHOUSE_DOMAIN|g" {} \\;\n\
find /app/web/.next -type f -name "*.js" -exec sed -i "s|https://edu.adradviser.ro|$NEXT_PUBLIC_LEARNHOUSE_DOMAIN|g" {} \\;\n\
find /app/web/.next -type f -name "*.js" -exec sed -i "s|//edu.adradviser.ro|//$DOMAIN_ONLY|g" {} \\;\n\
find /app/web/.next -type f -name "*.js" -exec sed -i "s|\"href\":\"http://edu.adradviser.ro|\"href\":\"$NEXT_PUBLIC_LEARNHOUSE_DOMAIN|g" {} \\;\n\
find /app/web/.next -type f -name "*.js" -exec sed -i "s|https://edu.adradviser.ro|$NEXT_PUBLIC_LEARNHOUSE_DOMAIN|g" {} \\;\n\
find /app/web/.next -type f -name "*.html" -exec sed -i "s|http://edu.adradviser.ro|$NEXT_PUBLIC_LEARNHOUSE_DOMAIN|g" {} \\;\n\
find /app/web/.next -type f -name "*.html" -exec sed -i "s|https://edu.adradviser.ro|$NEXT_PUBLIC_LEARNHOUSE_DOMAIN|g" {} \\;\n\
\n\
# Replace absolute URL paths\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\
\n\
# Replace hardcoded href values\n\
find /app/web/.next -type f -name "*.js" -exec sed -i "s|href:\\\"http://edu.adradviser.ro|href:\\\"$NEXT_PUBLIC_LEARNHOUSE_DOMAIN|g" {} \\;\n\
find /app/web/.next -type f -name "*.js" -exec sed -i "s|href:\\\"https://edu.adradviser.ro|href:\\\"$NEXT_PUBLIC_LEARNHOUSE_DOMAIN|g" {} \\;\n\
\n\
echo "URL and domain patching completed using: $NEXT_PUBLIC_LEARNHOUSE_DOMAIN"\n\
\n\
# Verify the changes\n\
echo "Verification of patched files:"\n\
grep -r "edu.adradviser.ro" /app/web/.next --include="*.js" | head -5 || echo "No references to edu.adradviser.ro found (good)"\n\
fi\n\
\n\
echo "Starting application..."\n\
sh /app/start.sh' > /app/patched-start.sh && chmod +x /app/patched-start.sh
# Use the patched start script

View file

View file

@ -1,5 +1,6 @@
import os
from fastapi import APIRouter
import subprocess
from fastapi import APIRouter, Request
from config.config import get_learnhouse_config
router = APIRouter()
@ -9,10 +10,67 @@ async def debug_deployment():
"""Debug endpoint for deployment verification and isolation testing"""
learnhouse_config = get_learnhouse_config()
# Parse database host safely
db_host = "unknown"
if '@' in learnhouse_config.database_config.sql_connection_string:
try:
parts = learnhouse_config.database_config.sql_connection_string.split('@')
if len(parts) > 1:
host_parts = parts[1].split('/')
if len(host_parts) > 0:
db_host = host_parts[0]
except Exception:
pass
# Parse redis host safely
redis_host = "unknown"
if '@' in learnhouse_config.redis_config.redis_connection_string:
try:
parts = learnhouse_config.redis_config.redis_connection_string.split('@')
if len(parts) > 1:
host_parts = parts[1].split(':')
if len(host_parts) > 0:
redis_host = host_parts[0]
except Exception:
pass
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"
"database_host": db_host,
"redis_host": redis_host,
"database_name": learnhouse_config.database_config.sql_connection_string.split('/')[-1] if '/' in learnhouse_config.database_config.sql_connection_string else "unknown",
"env_vars": {
"NEXT_PUBLIC_LEARNHOUSE_DOMAIN": os.environ.get('NEXT_PUBLIC_LEARNHOUSE_DOMAIN', 'NOT_SET'),
"NEXT_PUBLIC_LEARNHOUSE_API_URL": os.environ.get('NEXT_PUBLIC_LEARNHOUSE_API_URL', 'NOT_SET')
}
}
@router.get("/urls")
async def debug_urls(request: Request):
"""Debug endpoint to detect hardcoded URLs in NextJS bundle"""
try:
# This only works if Next.js files are accessible from the API container
result = subprocess.run(
["find", "/app/web/.next", "-type", "f", "-name", "*.js", "-exec", "grep", "-o", "http://edu.adradviser.ro[^\"']*", "{}", ";"],
capture_output=True, text=True, timeout=5
)
hardcoded_urls = list(set(result.stdout.strip().split('\n'))) if result.stdout.strip() else []
# Get the current domain for comparison
current_domain = os.environ.get('NEXT_PUBLIC_LEARNHOUSE_DOMAIN', 'unknown')
return {
"detected_hardcoded_urls": hardcoded_urls,
"current_domain": current_domain,
"client_host": request.client.host,
"headers": dict(request.headers),
"deployment_name": os.environ.get('DEPLOYMENT_NAME', 'NOT_SET')
}
except Exception as e:
return {
"error": str(e),
"message": "Could not scan for hardcoded URLs",
"deployment_name": os.environ.get('DEPLOYMENT_NAME', 'NOT_SET')
}

0
deploy-isolation-fix.sh Executable file
View file

171
verify-db-isolation.sh Executable file
View file

@ -0,0 +1,171 @@
#!/bin/bash
# Database Isolation Verification Script
# This script will verify database isolation between DEV and LIVE deployments
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}=== Database Isolation Verification Script ===${NC}"
echo -e "${YELLOW}This script will verify database isolation between DEV and LIVE deployments${NC}"
echo ""
# First check API debug endpoints for database information
echo -e "${BLUE}Checking API debug endpoints for database information...${NC}"
DEV_URL="https://adr-lms.whitex.cloud"
LIVE_URL="https://edu.adradviser.ro"
DEV_DEBUG=$(curl -s -m 10 -k "$DEV_URL/api/v1/debug/deployment" || echo '{"error":"Failed to connect"}')
LIVE_DEBUG=$(curl -s -m 10 -k "$LIVE_URL/api/v1/debug/deployment" || echo '{"error":"Failed to connect"}')
# Extract values using Python if available
if command -v python3 &> /dev/null; then
echo -e "${GREEN}${NC} Python3 available for JSON parsing"
DEV_DB_HOST=$(echo "$DEV_DEBUG" | python3 -c "import sys, json; print(json.load(sys.stdin).get('database_host', 'unknown'))" 2>/dev/null)
LIVE_DB_HOST=$(echo "$LIVE_DEBUG" | python3 -c "import sys, json; print(json.load(sys.stdin).get('database_host', 'unknown'))" 2>/dev/null)
DEV_DB_NAME=$(echo "$DEV_DEBUG" | python3 -c "import sys, json; print(json.load(sys.stdin).get('database_name', 'unknown'))" 2>/dev/null)
LIVE_DB_NAME=$(echo "$LIVE_DEBUG" | python3 -c "import sys, json; print(json.load(sys.stdin).get('database_name', 'unknown'))" 2>/dev/null)
echo -e "${YELLOW}From API Debug:${NC}"
echo -e "DEV DB: Host=${DEV_DB_HOST}, Name=${DEV_DB_NAME}"
echo -e "LIVE DB: Host=${LIVE_DB_HOST}, Name=${LIVE_DB_NAME}"
if [ "$DEV_DB_HOST" == "$LIVE_DB_HOST" ]; then
echo -e "${RED}⚠️ WARNING: Both deployments using same database host: $DEV_DB_HOST${NC}"
else
if [ "$DEV_DB_HOST" != "unknown" ] && [ "$LIVE_DB_HOST" != "unknown" ]; then
echo -e "${GREEN}✓ Database hosts are properly isolated between deployments${NC}"
else
echo -e "${YELLOW}⚠️ Could not verify database hosts from API - falling back to manual checking${NC}"
fi
fi
else
echo -e "${YELLOW}Python3 not available for JSON parsing - falling back to manual checking${NC}"
fi
echo -e "\n${BLUE}Continuing with direct database verification...${NC}"
# Function to extract database connection details from environment variables
extract_db_details() {
# Get connection string from environment
local conn_string="$1"
# Extract username, password, host, port, and database name
local username=$(echo "$conn_string" | sed -E 's/^postgresql:\/\/([^:]+):.*/\1/')
local password=$(echo "$conn_string" | sed -E 's/^postgresql:\/\/[^:]+:([^@]+)@.*/\1/')
local host=$(echo "$conn_string" | sed -E 's/^postgresql:\/\/[^@]+@([^:]+):.*/\1/')
local port=$(echo "$conn_string" | sed -E 's/^postgresql:\/\/[^@]+@[^:]+:([^\/]+)\/.*/\1/')
local dbname=$(echo "$conn_string" | sed -E 's/^postgresql:\/\/[^@]+@[^\/]+\/([^?]+).*/\1/')
echo "Username: $username"
echo "Password: [HIDDEN]"
echo "Host: $host"
echo "Port: $port"
echo "Database: $dbname"
# Return values in a specific format for later use
echo "$host|$port|$dbname|$username|$password"
}
# Function to test database connection
test_db_connection() {
local details="$1"
local host=$(echo "$details" | cut -d'|' -f1)
local port=$(echo "$details" | cut -d'|' -f2)
local dbname=$(echo "$details" | cut -d'|' -f3)
local username=$(echo "$details" | cut -d'|' -f4)
local password=$(echo "$details" | cut -d'|' -f5)
echo -e "${BLUE}Testing connection to $dbname on $host:$port...${NC}"
# Try to connect and run a simple query
if PGPASSWORD="$password" psql -h "$host" -p "$port" -U "$username" -d "$dbname" -c "SELECT 1;" > /dev/null 2>&1; then
echo -e "${GREEN}✓ Successfully connected to database $dbname on $host${NC}"
return 0
else
echo -e "${RED}✗ Failed to connect to database $dbname on $host${NC}"
return 1
fi
}
# Function to test if two databases share the same server
test_db_isolation() {
local dev_details="$1"
local live_details="$2"
local dev_host=$(echo "$dev_details" | cut -d'|' -f1)
local live_host=$(echo "$live_details" | cut -d'|' -f1)
echo -e "${BLUE}Checking database isolation...${NC}"
if [ "$dev_host" == "$live_host" ]; then
echo -e "${RED}✗ ISOLATION FAILURE: DEV and LIVE environments are using the same database host: $dev_host${NC}"
echo -e "${RED} This will cause cross-deployment contamination!${NC}"
return 1
else
echo -e "${GREEN}✓ Database isolation confirmed: DEV($dev_host) ≠ LIVE($live_host)${NC}"
return 0
fi
}
# Main execution
# Get connection strings from environment or prompt user
if [ -z "$DEV_DB_URL" ]; then
echo -e "${YELLOW}DEV database connection string not found in environment.${NC}"
echo -e "Enter DEV database connection string (postgresql://user:pass@host:port/dbname):"
read -p "> " DEV_DB_URL
fi
if [ -z "$LIVE_DB_URL" ]; then
echo -e "${YELLOW}LIVE database connection string not found in environment.${NC}"
echo -e "Enter LIVE database connection string (postgresql://user:pass@host:port/dbname):"
read -p "> " LIVE_DB_URL
fi
# Extract connection details
echo -e "\n${BLUE}DEV Database Details:${NC}"
DEV_DETAILS=$(extract_db_details "$DEV_DB_URL")
echo ""
echo -e "${BLUE}LIVE Database Details:${NC}"
LIVE_DETAILS=$(extract_db_details "$LIVE_DB_URL")
echo ""
# Test connections
DEV_CONNECTION_OK=false
LIVE_CONNECTION_OK=false
if test_db_connection "$DEV_DETAILS"; then
DEV_CONNECTION_OK=true
fi
if test_db_connection "$LIVE_DETAILS"; then
LIVE_CONNECTION_OK=true
fi
# If both connections work, test isolation
if $DEV_CONNECTION_OK && $LIVE_CONNECTION_OK; then
test_db_isolation "$DEV_DETAILS" "$LIVE_DETAILS"
ISOLATION_RESULT=$?
else
echo -e "${YELLOW}⚠️ Could not verify isolation because one or both database connections failed.${NC}"
ISOLATION_RESULT=2
fi
echo ""
echo -e "${BLUE}=== Verification Results ===${NC}"
if [ $ISOLATION_RESULT -eq 0 ]; then
echo -e "${GREEN}✓ SUCCESS: Databases are properly isolated${NC}"
elif [ $ISOLATION_RESULT -eq 1 ]; then
echo -e "${RED}✗ FAILURE: Databases are not isolated!${NC}"
echo -e "${YELLOW}Action required: Update your database connection strings to use different hosts.${NC}"
echo -e "See DATABASE_ISOLATION_FIX.md for details."
else
echo -e "${YELLOW}⚠️ INCONCLUSIVE: Could not verify isolation${NC}"
echo -e "Fix connection issues and try again."
fi
exit $ISOLATION_RESULT

View file

@ -1,102 +1,177 @@
#!/bin/bash
echo "🔍 LearnHouse Deployment Isolation Verification"
echo "==============================================="
# Colors for better output
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}🔍 LearnHouse Deployment Isolation Verification${NC}"
echo -e "${BLUE}===============================================${NC}"
# Check DEV deployment
echo ""
echo "📋 DEV Deployment (adr-lms.whitex.cloud):"
echo -e "${YELLOW}📋 DEV Deployment (adr-lms.whitex.cloud):${NC}"
echo "----------------------------------------"
echo "Testing API connection..."
DEV_RESPONSE=$(curl -s https://adr-lms.whitex.cloud/api/v1/debug/deployment 2>/dev/null)
DEV_ROOT=$(curl -s https://adr-lms.whitex.cloud/ 2>/dev/null | head -200)
DEV_RESPONSE=$(curl -s -k https://adr-lms.whitex.cloud/api/v1/debug/deployment 2>/dev/null)
DEV_HEALTH=$(curl -s -k https://adr-lms.whitex.cloud/api/health 2>/dev/null)
DEV_ROOT=$(curl -s -k https://adr-lms.whitex.cloud/ 2>/dev/null | head -200)
if [ $? -eq 0 ]; then
echo "✅ DEV API accessible"
echo -e "${GREEN}✅ DEV API accessible${NC}"
echo " Health: $DEV_HEALTH"
echo " Debug Response: $DEV_RESPONSE"
if [[ "$DEV_ROOT" == *"LearnHouse"* ]] || [[ "$DEV_ROOT" == *"React"* ]] || [[ "$DEV_ROOT" == *"Next"* ]]; then
echo "✅ DEV Frontend serving properly"
echo -e "${GREEN}✅ DEV Frontend serving properly${NC}"
else
echo "⚠️ DEV Frontend response unclear"
echo -e "${YELLOW}⚠️ DEV Frontend response unclear${NC}"
echo " Root response (first 100 chars): ${DEV_ROOT:0:100}"
fi
else
echo "❌ DEV API not accessible"
echo -e "${RED}❌ DEV API not accessible${NC}"
fi
echo ""
echo "Testing frontend..."
DEV_FRONTEND=$(curl -s -o /dev/null -w "%{http_code}" https://adr-lms.whitex.cloud/ 2>/dev/null)
DEV_FRONTEND=$(curl -s -k -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)"
echo -e "${GREEN}✅ DEV Frontend accessible (HTTP $DEV_FRONTEND)${NC}"
else
echo "❌ DEV Frontend issue (HTTP $DEV_FRONTEND)"
echo -e "${RED}❌ DEV Frontend issue (HTTP $DEV_FRONTEND)${NC}"
fi
# Check LIVE deployment
echo ""
echo "📋 LIVE Deployment (edu.adradviser.ro):"
echo -e "${YELLOW}📋 LIVE Deployment (edu.adradviser.ro):${NC}"
echo "---------------------------------------"
echo "Testing API connection..."
LIVE_RESPONSE=$(curl -s https://edu.adradviser.ro/api/v1/debug/deployment 2>/dev/null)
LIVE_ROOT=$(curl -s https://edu.adradviser.ro/ 2>/dev/null | head -200)
LIVE_RESPONSE=$(curl -s -k https://edu.adradviser.ro/api/v1/debug/deployment 2>/dev/null)
LIVE_HEALTH=$(curl -s -k https://edu.adradviser.ro/api/health 2>/dev/null)
LIVE_ROOT=$(curl -s -k https://edu.adradviser.ro/ 2>/dev/null | head -200)
if [ $? -eq 0 ]; then
echo "✅ LIVE API accessible"
echo -e "${GREEN}✅ LIVE API accessible${NC}"
echo " Health: $LIVE_HEALTH"
echo " Debug Response: $LIVE_RESPONSE"
if [[ "$LIVE_ROOT" == *"LearnHouse"* ]] || [[ "$LIVE_ROOT" == *"React"* ]] || [[ "$LIVE_ROOT" == *"Next"* ]]; then
echo "✅ LIVE Frontend serving properly"
echo -e "${GREEN}✅ LIVE Frontend serving properly${NC}"
else
echo "⚠️ LIVE Frontend response unclear"
echo -e "${YELLOW}⚠️ LIVE Frontend response unclear${NC}"
echo " Root response (first 100 chars): ${LIVE_ROOT:0:100}"
fi
else
echo "❌ LIVE API not accessible"
echo -e "${RED}❌ LIVE API not accessible${NC}"
fi
echo ""
echo "Testing frontend..."
LIVE_FRONTEND=$(curl -s -o /dev/null -w "%{http_code}" https://edu.adradviser.ro/ 2>/dev/null)
LIVE_FRONTEND=$(curl -s -k -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)"
echo -e "${GREEN}✅ LIVE Frontend accessible (HTTP $LIVE_FRONTEND)${NC}"
else
echo "❌ LIVE Frontend issue (HTTP $LIVE_FRONTEND)"
echo -e "${RED}❌ LIVE Frontend issue (HTTP $LIVE_FRONTEND)${NC}"
fi
# Analysis
echo ""
echo "🔍 Cross-Deployment Isolation Analysis:"
echo -e "${BLUE}🔍 Cross-Deployment Isolation Analysis:${NC}"
echo "========================================"
# Check for hardcoded URLs
echo -e "\n${BLUE}Checking for hardcoded LIVE URLs in DEV frontend...${NC}"
LIVE_URLS_IN_DEV=$(echo "$DEV_ROOT" | grep -o "http://edu.adradviser.ro[^\"']*\|https://edu.adradviser.ro[^\"']*" | sort -u)
if [[ -n "$LIVE_URLS_IN_DEV" ]]; then
echo -e "${RED}⚠️ WARNING: Found hardcoded LIVE URLs in DEV frontend:${NC}"
echo "$LIVE_URLS_IN_DEV"
else
echo -e "${GREEN}✅ No hardcoded LIVE URLs found in DEV frontend${NC}"
fi
# Check for courses UUIDs
DEV_COURSES=$(echo "$DEV_ROOT" | grep -o "course_[a-zA-Z0-9-]*" | sort -u)
LIVE_COURSES=$(echo "$LIVE_ROOT" | grep -o "course_[a-zA-Z0-9-]*" | sort -u)
echo -e "\n${BLUE}Course UUIDs found in deployments:${NC}"
echo -e "${YELLOW}DEV courses:${NC} $(echo $DEV_COURSES | tr '\n' ' ')"
echo -e "${YELLOW}LIVE courses:${NC} $(echo $LIVE_COURSES | tr '\n' ' ')"
# Find common courses
if [[ -n "$DEV_COURSES" && -n "$LIVE_COURSES" ]]; then
# Using grep to find common entries
COMMON_COURSES=""
for course in $DEV_COURSES; do
if echo "$LIVE_COURSES" | grep -q "$course"; then
COMMON_COURSES="$COMMON_COURSES $course"
fi
done
if [[ -n "$COMMON_COURSES" ]]; then
echo -e "${RED}⚠️ WARNING: Found shared courses between deployments (contamination):${NC}"
echo "$COMMON_COURSES"
else
echo -e "${GREEN}✅ No shared courses found between deployments${NC}"
fi
fi
# 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 command -v python3 >/dev/null 2>&1; then
echo -e "\n${BLUE}Database connection analysis:${NC}"
if [[ "$DEV_RESPONSE" == *"database_host"* ]]; then
DEV_DB=$(echo "$DEV_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin).get('database_host', 'unknown'))" 2>/dev/null)
echo -e "DEV database: ${YELLOW}$DEV_DB${NC}"
else
echo -e "${RED}⚠️ Cannot analyze DEV database - debug endpoint not working${NC}"
fi
if [ "$DEV_DB" != "unknown" ] && [ "$LIVE_DB" != "unknown" ]; then
if [[ "$LIVE_RESPONSE" == *"database_host"* ]]; then
LIVE_DB=$(echo "$LIVE_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin).get('database_host', 'unknown'))" 2>/dev/null)
echo -e "LIVE database: ${YELLOW}$LIVE_DB${NC}"
else
echo -e "${RED}⚠️ Cannot analyze LIVE database - debug endpoint not working${NC}"
fi
if [[ -n "$DEV_DB" && -n "$LIVE_DB" && "$DEV_DB" != "unknown" && "$LIVE_DB" != "unknown" ]]; then
if [ "$DEV_DB" = "$LIVE_DB" ]; then
echo "⚠️ WARNING: Both deployments using same database host: $DEV_DB"
echo -e "${RED}⚠️ WARNING: Both deployments using same database host: $DEV_DB${NC}"
echo -e "${RED} This is likely the cause of cross-deployment contamination!${NC}"
else
echo "✅ Database isolation: DEV($DEV_DB) ≠ LIVE($LIVE_DB)"
echo -e "${GREEN}✅ Database isolation confirmed: DEV($DEV_DB) ≠ LIVE($LIVE_DB)${NC}"
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)
echo -e "\n${BLUE}Cookie domain analysis:${NC}"
if [[ "$DEV_RESPONSE" == *"cookie_domain"* ]]; then
DEV_COOKIE=$(echo "$DEV_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin).get('cookie_domain', 'unknown'))" 2>/dev/null)
echo -e "DEV cookie domain: ${YELLOW}$DEV_COOKIE${NC}"
else
echo -e "${RED}⚠️ Cannot analyze DEV cookie domain - debug endpoint not working${NC}"
fi
if [ "$DEV_COOKIE" != "unknown" ] && [ "$LIVE_COOKIE" != "unknown" ]; then
if [[ "$LIVE_RESPONSE" == *"cookie_domain"* ]]; then
LIVE_COOKIE=$(echo "$LIVE_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin).get('cookie_domain', 'unknown'))" 2>/dev/null)
echo -e "LIVE cookie domain: ${YELLOW}$LIVE_COOKIE${NC}"
else
echo -e "${RED}⚠️ Cannot analyze LIVE cookie domain - debug endpoint not working${NC}"
fi
if [[ -n "$DEV_COOKIE" && -n "$LIVE_COOKIE" && "$DEV_COOKIE" != "unknown" && "$LIVE_COOKIE" != "unknown" ]]; then
if [ "$DEV_COOKIE" = "$LIVE_COOKIE" ]; then
echo "⚠️ WARNING: Both deployments using same cookie domain: $DEV_COOKIE"
echo -e "${RED}⚠️ WARNING: Both deployments using same cookie domain: $DEV_COOKIE${NC}"
echo -e "${RED} This could cause session contamination between deployments!${NC}"
else
echo "✅ Cookie isolation: DEV($DEV_COOKIE) ≠ LIVE($LIVE_COOKIE)"
echo -e "${GREEN}✅ Cookie domain isolation confirmed: DEV($DEV_COOKIE) ≠ LIVE($LIVE_COOKIE)${NC}"
fi
fi
else
echo " Install 'jq' for detailed analysis"
echo -e "${YELLOW} Python3 not available for JSON analysis${NC}"
fi
echo ""
echo "🚀 Next Steps:"
echo -e "\n${BLUE}🚀 Next Steps:${NC}"
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 "1. If debug endpoints are not accessible, deploy the API changes first"
echo "2. Verify database connection strings are different between deployments"
echo "3. Check the Dockerfile_coolify for proper API URL replacement"
echo "4. Clear browser cache/cookies for both domains"
echo "5. Test in incognito mode to verify isolation"
echo "4. Check container logs: docker logs <container_name>"