From d32389a8ef38899c53c30714d0ecd23312220c9f Mon Sep 17 00:00:00 2001 From: WhiteX Date: Fri, 13 Jun 2025 00:12:15 +0300 Subject: [PATCH] Add LearnHouse Deployment Isolation Toolkit and debugging tools - Introduced comprehensive documentation for diagnosing and fixing deployment isolation issues between DEV and LIVE instances. - Implemented enhanced debug API endpoints for deployment verification, URL hardcoding detection, cookie isolation testing, and session configuration checks. - Created scripts for visual demonstration of cookie isolation, enhanced debugging deployment, and verification of NextAuth cookie isolation. - Developed a master isolation verification script to run all isolation checks in sequence and summarize results. - Added detailed README and environment variable guidelines for proper deployment isolation. --- DATABASE_ISOLATION_FIX.md | 28 ++- ENHANCED_DEBUG_TOOLS.md | 123 +++++++++++ ISOLATION_IMPLEMENTATION_CHECKLIST.md | 63 ++++-- ISOLATION_IMPROVEMENTS.md | 74 +++++++ ISOLATION_TOOLKIT_README.md | 107 ++++++++++ apps/api/src/router.py | 4 +- apps/api/src/routers/debug.py | 169 ++++++++++++++-- apps/api/src/routers/debug_enhanced.py | 269 +++++++++++++++++++++++++ apps/web/app/auth/options.ts | 4 +- create-cookie-demo.sh | 264 ++++++++++++++++++++++++ deploy-enhanced-debug.sh | 67 ++++++ test-nextauth-cookie-isolation.sh | 94 +++++++++ verify-all-isolation.sh | 182 +++++++++++++++++ verify-enhanced-isolation.sh | 162 +++++++++++++++ 14 files changed, 1571 insertions(+), 39 deletions(-) create mode 100644 ENHANCED_DEBUG_TOOLS.md create mode 100644 ISOLATION_IMPROVEMENTS.md create mode 100644 ISOLATION_TOOLKIT_README.md create mode 100644 apps/api/src/routers/debug_enhanced.py create mode 100755 create-cookie-demo.sh create mode 100755 deploy-enhanced-debug.sh create mode 100755 test-nextauth-cookie-isolation.sh create mode 100755 verify-all-isolation.sh create mode 100755 verify-enhanced-isolation.sh diff --git a/DATABASE_ISOLATION_FIX.md b/DATABASE_ISOLATION_FIX.md index 5796c166..59033489 100644 --- a/DATABASE_ISOLATION_FIX.md +++ b/DATABASE_ISOLATION_FIX.md @@ -143,9 +143,31 @@ Added comprehensive debug endpoints: 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 +1. **Deploy the enhanced debug tools**: + ```bash + ./deploy-enhanced-debug.sh + ``` + +2. **Run the enhanced verification script** for comprehensive isolation checks: + ```bash + ./verify-enhanced-isolation.sh + ``` + +3. **Verify cookie isolation** using the dedicated cookie debug endpoint: + ```bash + curl -v https://adr-lms.whitex.cloud/api/v1/debug/cookies + curl -v https://edu.adradviser.ro/api/v1/debug/cookies + ``` + +4. **Check session configuration** to ensure proper isolation: + ```bash + curl https://adr-lms.whitex.cloud/api/v1/debug/session + curl https://edu.adradviser.ro/api/v1/debug/session + ``` + +5. **Test with incognito browsers** to ensure sessions don't cross-contaminate between deployments + +See `ENHANCED_DEBUG_TOOLS.md` for more detailed information on these debugging endpoints. ## Implementation Plan diff --git a/ENHANCED_DEBUG_TOOLS.md b/ENHANCED_DEBUG_TOOLS.md new file mode 100644 index 00000000..8716423a --- /dev/null +++ b/ENHANCED_DEBUG_TOOLS.md @@ -0,0 +1,123 @@ +# Enhanced Debug Endpoints for Isolation Troubleshooting + +This document describes the enhanced debugging tools available to diagnose cross-deployment isolation issues between DEV and LIVE environments. + +## Available Debug Endpoints + +The following endpoints are available for diagnosing isolation issues: + +### 1. Deployment Information + +**Endpoint:** `/api/v1/debug/deployment` + +This endpoint provides detailed information about the current deployment, including: +- Deployment name +- Hostname and container ID +- Database connection details (host, user, database name) +- Redis connection details +- Cookie domain configuration +- Environment variables related to deployment URLs + +**Example Usage:** +```bash +curl https://adr-lms.whitex.cloud/api/v1/debug/deployment +``` + +### 2. URL Hardcoding Detection + +**Endpoint:** `/api/v1/debug/urls` + +This endpoint scans the NextJS bundle for hardcoded URLs that could lead to cross-contamination between deployments: +- Detects references to both DEV and LIVE domains +- Identifies NextAuth configuration issues +- Shows environment variables related to API URLs + +**Example Usage:** +```bash +curl https://adr-lms.whitex.cloud/api/v1/debug/urls +``` + +### 3. Cookie Isolation Testing + +**Endpoint:** `/api/v1/debug/cookies` + +This endpoint tests cookie isolation by: +- Setting a test cookie with the current deployment name +- Detecting any test cookies from other deployments +- Reporting the cookie domain in use +- Showing headers from the request + +**Example Usage:** +```bash +curl https://adr-lms.whitex.cloud/api/v1/debug/cookies -v +``` + +### 4. Session Configuration Check + +**Endpoint:** `/api/v1/debug/session` + +This endpoint examines session-related configuration: +- Shows request headers related to origins +- Reports NextAuth URL configuration +- Indicates where session requests would be sent + +**Example Usage:** +```bash +curl https://adr-lms.whitex.cloud/api/v1/debug/session +``` + +## Using the Enhanced Verification Script + +We've also created an enhanced isolation verification script that checks both DEV and LIVE deployments and provides a summary of their isolation status: + +```bash +./verify-enhanced-isolation.sh +``` + +The script will: +1. Check deployment configuration on both environments +2. Test cookie isolation +3. Look for hardcoded URLs +4. Verify session configuration +5. Analyze database isolation +6. Provide a summary of isolation status + +## Resolving Isolation Issues + +If the verification indicates isolation issues, ensure the following settings are unique between deployments: + +1. **Database Connections**: Each deployment should use its own database + ``` + # DEV environment + LEARNHOUSE_SQL_CONNECTION_STRING=postgresql://learnhouse_dev:YOUR_DEV_PASSWORD@db-dev:5432/learnhouse_dev + + # LIVE environment + LEARNHOUSE_SQL_CONNECTION_STRING=postgresql://learnhouse:YOUR_LIVE_PASSWORD@db-live:5432/learnhouse + ``` + +2. **Cookie Domains**: Each deployment should have its own cookie domain + ``` + # DEV environment + LEARNHOUSE_COOKIE_DOMAIN=adr-lms.whitex.cloud + + # LIVE environment + LEARNHOUSE_COOKIE_DOMAIN=edu.adradviser.ro + ``` + +3. **Top Domain Configuration**: Ensure each deployment has the correct top domain + ``` + # DEV environment + NEXT_PUBLIC_LEARNHOUSE_TOP_DOMAIN=whitex.cloud + + # LIVE environment + NEXT_PUBLIC_LEARNHOUSE_TOP_DOMAIN=adradviser.ro + ``` + +4. **Deployment Name**: Set a descriptive name to help with debugging + ``` + # DEV environment + DEPLOYMENT_NAME=DEV + + # LIVE environment + DEPLOYMENT_NAME=LIVE + ``` diff --git a/ISOLATION_IMPLEMENTATION_CHECKLIST.md b/ISOLATION_IMPLEMENTATION_CHECKLIST.md index 37896f29..71cf4c66 100644 --- a/ISOLATION_IMPLEMENTATION_CHECKLIST.md +++ b/ISOLATION_IMPLEMENTATION_CHECKLIST.md @@ -18,7 +18,12 @@ We've identified that both DEV and LIVE deployments are accessing the same datab git pull origin dev ``` -- [ ] Verify the debug endpoint files exist: +- [ ] Deploy the enhanced debug tools first: + ```bash + ./deploy-enhanced-debug.sh + ``` + +- [ ] Verify the enhanced debug endpoints are working: ```bash ls -la apps/api/src/routers/debug.py ``` @@ -80,19 +85,37 @@ We've identified that both DEV and LIVE deployments are accessing the same datab ### Step 5: Verification -- [ ] Run verification scripts: +- [ ] Run the comprehensive isolation verification script: ```bash - ./verify-isolation.sh - ./verify-db-isolation.sh + ./verify-all-isolation.sh + ``` + This will: + - Check deployment configuration + - Verify database isolation + - Test cookie isolation + - Check for hardcoded URLs + - Create a visual cookie isolation demo + +- [ ] For more detailed verification, run individual scripts: + ```bash + ./verify-enhanced-isolation.sh # Basic deployment checks + ./verify-db-isolation.sh # Database-specific checks + ./test-nextauth-cookie-isolation.sh # Cookie isolation tests + ``` + +- [ ] Test the visual cookie isolation demo: + ```bash + ./create-cookie-demo.sh + # Open the resulting HTML file in a browser ``` - [ ] Access debug endpoints directly: - DEV: https://adr-lms.whitex.cloud/api/v1/debug/deployment - LIVE: https://edu.adradviser.ro/api/v1/debug/deployment - -- [ ] Check URLs in frontend: - - DEV: https://adr-lms.whitex.cloud/api/v1/debug/urls - - LIVE: https://edu.adradviser.ro/api/v1/debug/urls + - DEV: https://adr-lms.whitex.cloud/api/v1/debug/cookies + - LIVE: https://edu.adradviser.ro/api/v1/debug/cookies + - DEV: https://adr-lms.whitex.cloud/api/v1/debug/session + - LIVE: https://edu.adradviser.ro/api/v1/debug/session - [ ] Test in incognito browsers to verify session isolation @@ -100,20 +123,30 @@ We've identified that both DEV and LIVE deployments are accessing the same datab If isolation issues persist after implementation: -1. **Verify Database Connections**: - - Confirm debug endpoints show different database hosts +1. **Use the Enhanced Debug Tools**: + - Look at the detailed reports in `/tmp/learnhouse-isolation-report/` + - Run specific tests: `./test-nextauth-cookie-isolation.sh` for cookie issues + - Check session configuration: `/api/v1/debug/session` endpoint + +2. **Verify Database Connections**: + - Confirm debug endpoints show different database hosts and names - Check actual database servers to confirm connections come from different sources + - Test with the database isolation script: `./verify-db-isolation.sh` -2. **Clear Browser Data**: +3. **Clear Browser Data**: - Use incognito mode or clear all cookies/cache for proper testing + - Try the cookie isolation demo to visually check cookie behavior -3. **Check Docker Network Isolation**: +4. **Check Docker Network Isolation**: - Ensure each deployment uses its own Docker network - Verify hostnames resolve to different IP addresses within containers -4. **Validate URL Patching**: +5. **Validate URL Patching**: - Run URL debug endpoint to confirm no hardcoded references remain + - Check the enhanced URL report in `/api/v1/debug/urls` endpoint For additional help, refer to the full documentation in: -- `DATABASE_ISOLATION_FIX.md` -- `DEPLOYMENT_TROUBLESHOOTING.md` +- `ENHANCED_DEBUG_TOOLS.md` - Detailed guide to all debug endpoints +- `DATABASE_ISOLATION_FIX.md` - Database isolation specifics +- `DEPLOYMENT_TROUBLESHOOTING.md` - General deployment troubleshooting +- `ISOLATION_TOOLKIT_README.md` - Overview of all isolation tools diff --git a/ISOLATION_IMPROVEMENTS.md b/ISOLATION_IMPROVEMENTS.md new file mode 100644 index 00000000..80df6cee --- /dev/null +++ b/ISOLATION_IMPROVEMENTS.md @@ -0,0 +1,74 @@ +# LearnHouse Isolation Fix: Improvements Summary + +We've developed a comprehensive set of tools, scripts, and documentation to help diagnose and fix deployment isolation issues between DEV and LIVE instances. Here's a summary of the improvements: + +## 1. Enhanced Debug Endpoints + +We expanded the API debug capabilities significantly: + +- **`/api/v1/debug/deployment`**: Enhanced with detailed database, Redis, container, and hostname information +- **`/api/v1/debug/urls`**: Improved to detect cross-contamination from both domains and categorize findings +- **`/api/v1/debug/cookies`**: New endpoint to test cookie isolation and detect cross-deployment cookies +- **`/api/v1/debug/session`**: New endpoint to check session configuration and origins + +## 2. Verification Scripts + +We created several verification scripts for different aspects of isolation: + +- **`verify-enhanced-isolation.sh`**: Comprehensive isolation checks for all aspects of deployment +- **`test-nextauth-cookie-isolation.sh`**: Focused testing for NextAuth cookie isolation +- **`verify-all-isolation.sh`**: Master script that runs all verification checks and produces a report +- **`create-cookie-demo.sh`**: Visual tool to demonstrate and test cookie behavior in browsers + +## 3. Documentation + +- **`ENHANCED_DEBUG_TOOLS.md`**: Detailed guide to all debug endpoints and how to use them +- **`ISOLATION_TOOLKIT_README.md`**: Overview of all tools available for isolation testing +- **Updated `ISOLATION_IMPLEMENTATION_CHECKLIST.md`**: Comprehensive checklist with new tools +- **Updated `DATABASE_ISOLATION_FIX.md`**: Enhanced verification methods + +## 4. Developer Experience + +- Visual cookie isolation demo with browser-based testing +- HTML reports for easy sharing and analyzing of results +- Colored terminal output for easy interpretation of verification results +- Container and hostname information for infrastructure verification + +## 5. Implementation Details + +The specific code improvements include: + +1. **Enhanced database information**: + - Now shows database username, hostname and database name + - Extracts Redis instance information + +2. **Cookie isolation testing**: + - Sets test cookies with deployment name + - Checks if cookies from one deployment are visible to another + - Visual browser-based tool to demonstrate isolation + +3. **Session configuration verification**: + - Analyzes headers and environment variables that affect session behavior + - Shows where sessions would be sent based on current configuration + +4. **Comprehensive URL checking**: + - Categorizes URLs by domain to identify cross-contamination + - Reports specific instances of hardcoded URLs in the frontend + +## Usage + +To use these enhanced tools: + +1. Deploy the enhanced debug module: + ```bash + ./deploy-enhanced-debug.sh + ``` + +2. Run the comprehensive verification: + ```bash + ./verify-all-isolation.sh + ``` + +3. Check the reports generated in `/tmp/learnhouse-isolation-report/` + +These enhancements will make it much easier to diagnose and fix isolation issues between the DEV and LIVE LearnHouse deployments. diff --git a/ISOLATION_TOOLKIT_README.md b/ISOLATION_TOOLKIT_README.md new file mode 100644 index 00000000..9ab7fe7c --- /dev/null +++ b/ISOLATION_TOOLKIT_README.md @@ -0,0 +1,107 @@ +# LearnHouse Deployment Isolation Toolkit + +This toolkit provides comprehensive tools and documentation for diagnosing and fixing deployment isolation issues between DEV and LIVE LearnHouse instances. + +## Background + +We identified cross-deployment contamination issues between DEV (adr-lms.whitex.cloud) and LIVE (edu.adradviser.ro) deployments, including: + +- Data contamination (both deployments accessing the same database) +- Session mixing (cookies being shared between deployments) +- Inconsistent user experience (hardcoded URLs pointing to the wrong environment) + +## Isolation Toolkit Components + +### Documentation + +1. **[ISOLATION_IMPLEMENTATION_CHECKLIST.md](./ISOLATION_IMPLEMENTATION_CHECKLIST.md)** + Step-by-step checklist for implementing complete isolation between deployments. + +2. **[DATABASE_ISOLATION_FIX.md](./DATABASE_ISOLATION_FIX.md)** + Detailed explanation of database isolation issues and how to fix them. + +3. **[DEPLOYMENT_TROUBLESHOOTING.md](./DEPLOYMENT_TROUBLESHOOTING.md)** + Guide for troubleshooting deployment and configuration issues. + +4. **[ENHANCED_DEBUG_TOOLS.md](./ENHANCED_DEBUG_TOOLS.md)** + Documentation for the enhanced debugging endpoints. + +5. **[COOLIFY_ENV_VARS.md](./COOLIFY_ENV_VARS.md)** + Environment variable templates for Coolify deployments. + +### Debugging Tools + +1. **Debug API Endpoints** + - `/api/v1/debug/deployment` - Get detailed deployment configuration + - `/api/v1/debug/urls` - Scan for hardcoded URLs in the frontend bundle + - `/api/v1/debug/cookies` - Test cookie isolation between deployments + - `/api/v1/debug/session` - Verify session configuration + +2. **Verification Scripts** + - `verify-isolation.sh` - Basic isolation verification + - `verify-enhanced-isolation.sh` - Comprehensive isolation checks + - `verify-db-isolation.sh` - Database-specific isolation verification + - `test-nextauth-cookie-isolation.sh` - NextAuth cookie isolation test + +3. **Visual Demonstration Tools** + - `create-cookie-demo.sh` - Creates an HTML tool to visually demonstrate cookie isolation + +### Deployment Scripts + +1. **`deploy-enhanced-debug.sh`** + Deploys the enhanced debugging endpoints to diagnose isolation issues. + +2. **`deploy-isolation-fix.sh`** + Applies the complete isolation fixes to both deployments. + +## Getting Started + +1. **Deploy debugging tools:** + ```bash + ./deploy-enhanced-debug.sh + ``` + +2. **Run the enhanced isolation verification:** + ```bash + ./verify-enhanced-isolation.sh + ``` + +3. **Test cookie isolation:** + ```bash + ./test-nextauth-cookie-isolation.sh + ``` + +4. **Create a visual cookie isolation demo:** + ```bash + ./create-cookie-demo.sh + # Then open cookie-isolation-demo.html in your browser + ``` + +5. **Follow the implementation checklist:** + See [ISOLATION_IMPLEMENTATION_CHECKLIST.md](./ISOLATION_IMPLEMENTATION_CHECKLIST.md) + +## Key Environment Variables for Isolation + +For proper isolation, ensure each deployment has unique values for these variables: + +### DEV Environment +``` +DEPLOYMENT_NAME=DEV +LEARNHOUSE_SQL_CONNECTION_STRING=postgresql://learnhouse_dev:PASSWORD@db-dev:5432/learnhouse_dev +LEARNHOUSE_COOKIE_DOMAIN=adr-lms.whitex.cloud +NEXT_PUBLIC_LEARNHOUSE_DOMAIN=adr-lms.whitex.cloud +NEXT_PUBLIC_LEARNHOUSE_TOP_DOMAIN=whitex.cloud +``` + +### LIVE Environment +``` +DEPLOYMENT_NAME=LIVE +LEARNHOUSE_SQL_CONNECTION_STRING=postgresql://learnhouse:PASSWORD@db-live:5432/learnhouse +LEARNHOUSE_COOKIE_DOMAIN=edu.adradviser.ro +NEXT_PUBLIC_LEARNHOUSE_DOMAIN=edu.adradviser.ro +NEXT_PUBLIC_LEARNHOUSE_TOP_DOMAIN=adradviser.ro +``` + +## Troubleshooting + +If you encounter issues during the isolation process, refer to [DEPLOYMENT_TROUBLESHOOTING.md](./DEPLOYMENT_TROUBLESHOOTING.md). diff --git a/apps/api/src/router.py b/apps/api/src/router.py index dae5b019..1fbc95b5 100644 --- a/apps/api/src/router.py +++ b/apps/api/src/router.py @@ -2,7 +2,9 @@ import os from fastapi import APIRouter, Depends from src.routers import health from src.routers import usergroups -from src.routers import dev, trail, users, auth, orgs, roles, search, debug +from src.routers import dev, trail, users, auth, orgs, roles, search +# Use enhanced debug module with improved isolation diagnostics +from src.routers import debug_enhanced as debug from src.routers.ai import ai from src.routers.courses import chapters, collections, courses, assignments, certifications from src.routers.courses.activities import activities, blocks diff --git a/apps/api/src/routers/debug.py b/apps/api/src/routers/debug.py index 81377879..c82e062e 100644 --- a/apps/api/src/routers/debug.py +++ b/apps/api/src/routers/debug.py @@ -1,6 +1,8 @@ import os +import json +import socket import subprocess -from fastapi import APIRouter, Request +from fastapi import APIRouter, Request, Response from config.config import get_learnhouse_config router = APIRouter() @@ -12,18 +14,32 @@ async def debug_deployment(): # Parse database host safely db_host = "unknown" + db_user = "unknown" + db_name = "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('/') + # Split out username and host parts + auth_host_parts = learnhouse_config.database_config.sql_connection_string.split('@') + if len(auth_host_parts) > 1: + # Extract username + auth_parts = auth_host_parts[0].split('//') + if len(auth_parts) > 1: + user_parts = auth_parts[1].split(':') + if len(user_parts) > 0: + db_user = user_parts[0] + + # Extract host and database name + host_parts = auth_host_parts[1].split('/') if len(host_parts) > 0: db_host = host_parts[0] - except Exception: + if len(host_parts) > 1: + db_name = host_parts[1] + except Exception as e: pass # Parse redis host safely redis_host = "unknown" + redis_db = "unknown" if '@' in learnhouse_config.redis_config.redis_connection_string: try: parts = learnhouse_config.redis_config.redis_connection_string.split('@') @@ -31,19 +47,51 @@ async def debug_deployment(): host_parts = parts[1].split(':') if len(host_parts) > 0: redis_host = host_parts[0] + if len(host_parts) > 1 and '/' in host_parts[1]: + redis_db = host_parts[1].split('/')[1] except Exception: pass + # Get hostname information + import socket + hostname = "unknown" + try: + hostname = socket.gethostname() + except: + pass + + # Get process and container info + container_id = "unknown" + try: + # Try to get container ID from cgroup + with open('/proc/self/cgroup', 'r') as f: + for line in f: + if 'docker' in line: + container_id = line.strip().split('/')[-1] + break + except: + pass + return { "deployment_name": os.environ.get('DEPLOYMENT_NAME', 'NOT_SET'), + "hostname": hostname, + "container_id": container_id, "cookie_domain": learnhouse_config.hosting_config.cookie_config.domain, "api_domain": learnhouse_config.hosting_config.domain, - "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", + "database": { + "host": db_host, + "user": db_user, + "name": db_name, + }, + "redis": { + "host": redis_host, + "db": redis_db + }, "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') + "NEXT_PUBLIC_LEARNHOUSE_API_URL": os.environ.get('NEXT_PUBLIC_LEARNHOUSE_API_URL', 'NOT_SET'), + "NEXT_PUBLIC_LEARNHOUSE_TOP_DOMAIN": os.environ.get('NEXT_PUBLIC_LEARNHOUSE_TOP_DOMAIN', 'NOT_SET'), + "LEARNHOUSE_COOKIE_DOMAIN": os.environ.get('LEARNHOUSE_COOKIE_DOMAIN', 'NOT_SET') } } @@ -51,21 +99,106 @@ async def debug_deployment(): 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 [] + # Define domains to check for hardcoding + known_domains = [ + "edu.adradviser.ro", # LIVE domain + "adr-lms.whitex.cloud" # DEV domain + ] - # Get the current domain for comparison - current_domain = os.environ.get('NEXT_PUBLIC_LEARNHOUSE_DOMAIN', 'unknown') + # Add any additional domains from environment variables + current_domain = os.environ.get('NEXT_PUBLIC_LEARNHOUSE_DOMAIN', '') + if current_domain and current_domain not in known_domains: + known_domains.append(current_domain) + # Build patterns for all domains to detect cross-contamination + patterns = [] + for domain in known_domains: + patterns.extend([ + f"http://{domain}[^\"']*", + f"https://{domain}[^\"']*", + f"//{domain}[^\"']*", + f"'{domain}'", + f"\"{domain}\"", + f"fetch\\(\"https://{domain}", + f"fetch\\(\"http://{domain}", + ]) + + # Add general patterns for NextAuth configuration + patterns.extend([ + "\"/api/auth/session\"", + "\"auth/session\"", + "fetch\\(\"/api/auth", + "domain:\"[^\"]*\"", + "baseUrl:\"[^\"]*\"", + "basePath:\"[^\"]*\"", + "NEXTAUTH_URL=\"[^\"]*\"", + "NEXTAUTH_URL='[^']*'" + ]) + + all_urls = [] + domain_matches = {domain: [] for domain in known_domains} + + # Search for URLs in JS files + for pattern in patterns: + result = subprocess.run( + ["find", "/app/web/.next", "-type", "f", "-name", "*.js", "-exec", "grep", "-o", pattern, "{}", ";"], + capture_output=True, text=True, timeout=10 + ) + if result.stdout.strip(): + found_urls = list(set(result.stdout.strip().split('\n'))) + all_urls.extend(found_urls) + + # Categorize URLs by domain + for url in found_urls: + for domain in known_domains: + if domain in url: + domain_matches[domain].append(url) + + # Look for NextAuth configuration + auth_configs = [] + try: + auth_result = subprocess.run( + ["find", "/app/web/.next", "-type", "f", "-name", "*.js", "-exec", "grep", "-o", "NEXTAUTH_URL[^,}]*", "{}", ";"], + capture_output=True, text=True, timeout=5 + ) + if auth_result.stdout.strip(): + auth_configs = list(set(auth_result.stdout.strip().split('\n'))) + except Exception: + pass + + # Gather environment variable information + 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'), + "NEXT_PUBLIC_API_URL": os.environ.get('NEXT_PUBLIC_API_URL', 'NOT_SET'), + "NEXTAUTH_URL": os.environ.get('NEXTAUTH_URL', 'NOT_SET'), + "NEXT_PUBLIC_LEARNHOUSE_TOP_DOMAIN": os.environ.get('NEXT_PUBLIC_LEARNHOUSE_TOP_DOMAIN', 'NOT_SET'), + "LEARNHOUSE_COOKIE_DOMAIN": os.environ.get('LEARNHOUSE_COOKIE_DOMAIN', 'NOT_SET') + } + + # Get the top domain from an environment variable or extract from current domain + top_domain = os.environ.get('NEXT_PUBLIC_LEARNHOUSE_TOP_DOMAIN', '') + if not top_domain and current_domain: + parts = current_domain.split('.') + if len(parts) >= 2: + top_domain = '.'.join(parts[-2:]) + return { - "detected_hardcoded_urls": hardcoded_urls, + "detected_hardcoded_urls": all_urls, + "domain_specific_matches": domain_matches, + "nextauth_configs": auth_configs, "current_domain": current_domain, + "top_domain": top_domain, + "env_vars": env_vars, "client_host": request.client.host, "headers": dict(request.headers), + "deployment_name": os.environ.get('DEPLOYMENT_NAME', 'NOT_SET'), + "request_url": str(request.url) + } + except Exception as e: + return { + "error": str(e), + "message": "Could not scan for hardcoded URLs", "deployment_name": os.environ.get('DEPLOYMENT_NAME', 'NOT_SET') } except Exception as e: diff --git a/apps/api/src/routers/debug_enhanced.py b/apps/api/src/routers/debug_enhanced.py new file mode 100644 index 00000000..c2fa6cda --- /dev/null +++ b/apps/api/src/routers/debug_enhanced.py @@ -0,0 +1,269 @@ +import os +import json +import socket +import subprocess +from fastapi import APIRouter, Request, Response +from config.config import get_learnhouse_config + +router = APIRouter() + +@router.get("/deployment") +async def debug_deployment(): + """Debug endpoint for deployment verification and isolation testing""" + learnhouse_config = get_learnhouse_config() + + # Parse database host safely + db_host = "unknown" + db_user = "unknown" + db_name = "unknown" + if '@' in learnhouse_config.database_config.sql_connection_string: + try: + # Split out username and host parts + auth_host_parts = learnhouse_config.database_config.sql_connection_string.split('@') + if len(auth_host_parts) > 1: + # Extract username + auth_parts = auth_host_parts[0].split('//') + if len(auth_parts) > 1: + user_parts = auth_parts[1].split(':') + if len(user_parts) > 0: + db_user = user_parts[0] + + # Extract host and database name + host_parts = auth_host_parts[1].split('/') + if len(host_parts) > 0: + db_host = host_parts[0] + if len(host_parts) > 1: + db_name = host_parts[1] + except Exception as e: + pass + + # Parse redis host safely + redis_host = "unknown" + redis_db = "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] + if len(host_parts) > 1 and '/' in host_parts[1]: + redis_db = host_parts[1].split('/')[1] + except Exception: + pass + + # Get hostname information + hostname = "unknown" + try: + hostname = socket.gethostname() + except: + pass + + # Get process and container info + container_id = "unknown" + try: + # Try to get container ID from cgroup + with open('/proc/self/cgroup', 'r') as f: + for line in f: + if 'docker' in line: + container_id = line.strip().split('/')[-1] + break + except: + pass + + return { + "deployment_name": os.environ.get('DEPLOYMENT_NAME', 'NOT_SET'), + "hostname": hostname, + "container_id": container_id, + "cookie_domain": learnhouse_config.hosting_config.cookie_config.domain, + "api_domain": learnhouse_config.hosting_config.domain, + "database": { + "host": db_host, + "user": db_user, + "name": db_name, + }, + "redis": { + "host": redis_host, + "db": redis_db + }, + "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'), + "NEXT_PUBLIC_LEARNHOUSE_TOP_DOMAIN": os.environ.get('NEXT_PUBLIC_LEARNHOUSE_TOP_DOMAIN', 'NOT_SET'), + "LEARNHOUSE_COOKIE_DOMAIN": os.environ.get('LEARNHOUSE_COOKIE_DOMAIN', 'NOT_SET') + } + } + +@router.get("/urls") +async def debug_urls(request: Request): + """Debug endpoint to detect hardcoded URLs in NextJS bundle""" + try: + # Define domains to check for hardcoding + known_domains = [ + "edu.adradviser.ro", # LIVE domain + "adr-lms.whitex.cloud" # DEV domain + ] + + # Add any additional domains from environment variables + current_domain = os.environ.get('NEXT_PUBLIC_LEARNHOUSE_DOMAIN', '') + if current_domain and current_domain not in known_domains: + known_domains.append(current_domain) + + # Build patterns for all domains to detect cross-contamination + patterns = [] + for domain in known_domains: + patterns.extend([ + f"http://{domain}[^\"']*", + f"https://{domain}[^\"']*", + f"//{domain}[^\"']*", + f"'{domain}'", + f"\"{domain}\"", + f"fetch\\(\"https://{domain}", + f"fetch\\(\"http://{domain}", + ]) + + # Add general patterns for NextAuth configuration + patterns.extend([ + "\"/api/auth/session\"", + "\"auth/session\"", + "fetch\\(\"/api/auth", + "domain:\"[^\"]*\"", + "baseUrl:\"[^\"]*\"", + "basePath:\"[^\"]*\"", + "NEXTAUTH_URL=\"[^\"]*\"", + "NEXTAUTH_URL='[^']*'" + ]) + + all_urls = [] + domain_matches = {domain: [] for domain in known_domains} + + # Search for URLs in JS files + for pattern in patterns: + result = subprocess.run( + ["find", "/app/web/.next", "-type", "f", "-name", "*.js", "-exec", "grep", "-o", pattern, "{}", ";"], + capture_output=True, text=True, timeout=10 + ) + if result.stdout.strip(): + found_urls = list(set(result.stdout.strip().split('\n'))) + all_urls.extend(found_urls) + + # Categorize URLs by domain + for url in found_urls: + for domain in known_domains: + if domain in url: + domain_matches[domain].append(url) + + # Look for NextAuth configuration + auth_configs = [] + try: + auth_result = subprocess.run( + ["find", "/app/web/.next", "-type", "f", "-name", "*.js", "-exec", "grep", "-o", "NEXTAUTH_URL[^,}]*", "{}", ";"], + capture_output=True, text=True, timeout=5 + ) + if auth_result.stdout.strip(): + auth_configs = list(set(auth_result.stdout.strip().split('\n'))) + except Exception: + pass + + # Gather environment variable information + 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'), + "NEXT_PUBLIC_API_URL": os.environ.get('NEXT_PUBLIC_API_URL', 'NOT_SET'), + "NEXTAUTH_URL": os.environ.get('NEXTAUTH_URL', 'NOT_SET'), + "NEXT_PUBLIC_LEARNHOUSE_TOP_DOMAIN": os.environ.get('NEXT_PUBLIC_LEARNHOUSE_TOP_DOMAIN', 'NOT_SET'), + "LEARNHOUSE_COOKIE_DOMAIN": os.environ.get('LEARNHOUSE_COOKIE_DOMAIN', 'NOT_SET') + } + + # Get the top domain from an environment variable or extract from current domain + top_domain = os.environ.get('NEXT_PUBLIC_LEARNHOUSE_TOP_DOMAIN', '') + if not top_domain and current_domain: + parts = current_domain.split('.') + if len(parts) >= 2: + top_domain = '.'.join(parts[-2:]) + + return { + "detected_hardcoded_urls": all_urls, + "domain_specific_matches": domain_matches, + "nextauth_configs": auth_configs, + "current_domain": current_domain, + "top_domain": top_domain, + "env_vars": env_vars, + "client_host": request.client.host, + "headers": dict(request.headers), + "deployment_name": os.environ.get('DEPLOYMENT_NAME', 'NOT_SET'), + "request_url": str(request.url) + } + except Exception as e: + return { + "error": str(e), + "message": "Could not scan for hardcoded URLs", + "deployment_name": os.environ.get('DEPLOYMENT_NAME', 'NOT_SET') + } + +@router.get("/cookies") +async def debug_cookies(request: Request, response: Response): + """Debug endpoint to test cookie isolation and behavior""" + # Get current configuration + learnhouse_config = get_learnhouse_config() + cookie_domain = learnhouse_config.hosting_config.cookie_config.domain + deployment_name = os.environ.get('DEPLOYMENT_NAME', 'unknown') + + # Set a test cookie with the current configuration + response.set_cookie( + key=f"isolation-test-{deployment_name}", + value=deployment_name, + domain=cookie_domain, + httponly=True, + samesite="lax", + path="/" + ) + + # Try to read any existing isolation test cookies + cookies = request.cookies + isolation_cookies = {} + + for key, value in cookies.items(): + if key.startswith("isolation-test-"): + isolation_cookies[key] = value + + return { + "deployment_name": deployment_name, + "cookie_domain": cookie_domain, + "request_host": request.headers.get("host", "unknown"), + "detected_isolation_cookies": isolation_cookies, + "all_cookies": {k: "****" if not k.startswith("isolation-test") else v for k, v in cookies.items()}, + "top_domain": os.environ.get('NEXT_PUBLIC_LEARNHOUSE_TOP_DOMAIN', 'NOT_SET'), + "message": f"Set test cookie 'isolation-test-{deployment_name}={deployment_name}' with domain={cookie_domain}" + } + +@router.get("/session") +async def debug_session(request: Request): + """Debug endpoint to check session-related headers and environment variables""" + # Extract host information + host = request.headers.get("host", "unknown") + origin = request.headers.get("origin", "unknown") + referer = request.headers.get("referer", "unknown") + + # Extract NextAuth related information + nextauth_url = os.environ.get('NEXTAUTH_URL', 'NOT_SET') + nextauth_url_internal = os.environ.get('NEXTAUTH_URL_INTERNAL', 'NOT_SET') + + # Check if session requests would go to the correct place + session_destination = nextauth_url or f"https://{host}" + + return { + "deployment_name": os.environ.get('DEPLOYMENT_NAME', 'unknown'), + "request_headers": { + "host": host, + "origin": origin, + "referer": referer, + }, + "session_config": { + "NEXTAUTH_URL": nextauth_url, + "NEXTAUTH_URL_INTERNAL": nextauth_url_internal, + "detected_session_destination": session_destination + }, + "cookie_domain": get_learnhouse_config().hosting_config.cookie_config.domain, + "message": "This endpoint helps diagnose where NextAuth session data would be sent" + } diff --git a/apps/web/app/auth/options.ts b/apps/web/app/auth/options.ts index 50ee9f05..351693b1 100644 --- a/apps/web/app/auth/options.ts +++ b/apps/web/app/auth/options.ts @@ -67,8 +67,8 @@ export const nextAuthOptions = { httpOnly: true, sameSite: 'lax', path: '/', - // When working on localhost, the cookie domain must be omitted entirely (https://stackoverflow.com/a/1188145) - domain: `.${LEARNHOUSE_TOP_DOMAIN}`, + // When working on localhost or with different domains, use the current domain instead of a shared top domain + domain: process.env.LEARNHOUSE_COOKIE_DOMAIN || (LEARNHOUSE_TOP_DOMAIN === 'localhost' ? undefined : `.${LEARNHOUSE_TOP_DOMAIN}`), secure: !isDevEnv, }, }, diff --git a/create-cookie-demo.sh b/create-cookie-demo.sh new file mode 100755 index 00000000..58ae807d --- /dev/null +++ b/create-cookie-demo.sh @@ -0,0 +1,264 @@ +#!/bin/bash + +# Create a demonstration HTML file to visualize cookie isolation problems +# This script generates an HTML file that shows which cookies are visible across deployments + +echo "Creating cookie isolation visualization tool..." + +# Define HTML content +cat > /home/whitex/dev/github/learnhouse/cookie-isolation-demo.html << 'EOL' + + + + + + LearnHouse Cookie Isolation Test + + + +

LearnHouse Cookie Isolation Test

+ +
+

This tool helps visualize cookie isolation between DEV and LIVE LearnHouse deployments. + It will help you identify if cookies from one deployment are visible to the other, which + could lead to session contamination.

+
+ +
+

1. Set Test Cookies

+

First, set test cookies on both deployments:

+ + +
+
+ +
+

2. Test Cookie Isolation

+

Now check if cookies are properly isolated between deployments:

+ +
+ +

Results

+
+

Results will appear here after running tests...

+
+ + + + +EOL + +echo "Cookie isolation demonstration tool has been created at:" +echo "/home/whitex/dev/github/learnhouse/cookie-isolation-demo.html" +echo +echo "To use this tool:" +echo "1. Open the HTML file in a browser" +echo "2. Click 'Set DEV Cookie' and 'Set LIVE Cookie' buttons" +echo "3. Click 'Test Cookie Isolation' to see if cookies are properly isolated" +echo +echo "This tool demonstrates visually whether the cookie domains are properly isolated between deployments." diff --git a/deploy-enhanced-debug.sh b/deploy-enhanced-debug.sh new file mode 100755 index 00000000..08837ff1 --- /dev/null +++ b/deploy-enhanced-debug.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +# Script to deploy enhanced isolation debugging tools +# This script will update the debug endpoints on both DEV and LIVE deployments + +echo "====================================================================" +echo "LearnHouse Enhanced Debug Tools Deployment" +echo "====================================================================" + +# ANSI color codes +GREEN='\033[0;32m' +RED='\033[0;31m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Define git branches +DEV_BRANCH="isolation-debug" +MAIN_BRANCH="main" + +# Ensure we have the latest code +echo -e "${BLUE}Fetching latest code...${NC}" +git fetch origin +current_branch=$(git rev-parse --abbrev-ref HEAD) + +# Create a new branch for our changes +echo -e "${BLUE}Creating branch for debug tools...${NC}" +git checkout -b $DEV_BRANCH + +# Check if the debug files exist +if [ ! -f "apps/api/src/routers/debug_enhanced.py" ]; then + echo -e "${RED}Error: Enhanced debug module not found! Run the setup script first.${NC}" + git checkout $current_branch + exit 1 +fi + +# Stage and commit our changes +echo -e "${BLUE}Committing changes...${NC}" +git add apps/api/src/routers/debug_enhanced.py +git add apps/api/src/router.py +git add verify-enhanced-isolation.sh +git add ENHANCED_DEBUG_TOOLS.md +git commit -m "Add enhanced debug endpoints for deployment isolation troubleshooting" + +# Push to origin +echo -e "${BLUE}Pushing changes to origin...${NC}" +if git push -u origin $DEV_BRANCH; then + echo -e "${GREEN}Successfully pushed changes to origin/$DEV_BRANCH${NC}" +else + echo -e "${RED}Failed to push changes. Please check your git configuration.${NC}" + git checkout $current_branch + exit 1 +fi + +echo "" +echo "====================================================================" +echo -e "${GREEN}Deployment preparation completed!${NC}" +echo "" +echo -e "To deploy these changes:" +echo -e "1. Create a pull request from ${BLUE}$DEV_BRANCH${NC} to ${BLUE}$MAIN_BRANCH${NC}" +echo -e "2. After review and merge, deploy to both environments" +echo -e "3. Use ${BLUE}./verify-enhanced-isolation.sh${NC} to check isolation" +echo "" +echo -e "Documentation: See ${BLUE}ENHANCED_DEBUG_TOOLS.md${NC} for endpoint usage" +echo "====================================================================" + +# Return to original branch +git checkout $current_branch diff --git a/test-nextauth-cookie-isolation.sh b/test-nextauth-cookie-isolation.sh new file mode 100755 index 00000000..52452172 --- /dev/null +++ b/test-nextauth-cookie-isolation.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +# NextAuth Cookie Isolation Test Script +# Tests whether the NextAuth session cookies are properly isolated between deployments + +echo "==============================================================" +echo "NextAuth Cookie Isolation Test" +echo "==============================================================" + +# Define deployment URLs +DEV_URL="http://adr-lms.whitex.cloud" +LIVE_URL="http://edu.adradviser.ro" + +# Colors for output +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to check if curl is installed +if ! command -v curl &> /dev/null; then + echo -e "${RED}Error: curl is not installed. Please install curl first.${NC}" + exit 1 +fi + +# Function to check if jq is installed (for prettier output) +if ! command -v jq &> /dev/null; then + echo -e "${YELLOW}Warning: jq is not installed. JSON output will not be formatted.${NC}" + JQ_CMD="cat" +else + JQ_CMD="jq" +fi + +echo -e "${BLUE}Step 1: Checking NextAuth configuration in DEV environment...${NC}" +curl -s "${DEV_URL}/api/v1/debug/session" | $JQ_CMD +echo + +echo -e "${BLUE}Step 2: Checking NextAuth configuration in LIVE environment...${NC}" +curl -s "${LIVE_URL}/api/v1/debug/session" | $JQ_CMD +echo + +echo -e "${BLUE}Step 3: Testing cookie isolation with test cookies...${NC}" +echo "Setting test cookies on DEV deployment..." +curl -s -c /tmp/dev_cookies.txt "${DEV_URL}/api/v1/debug/cookies" > /dev/null +echo "Setting test cookies on LIVE deployment..." +curl -s -c /tmp/live_cookies.txt "${LIVE_URL}/api/v1/debug/cookies" > /dev/null + +echo -e "${BLUE}Step 4: Checking for cookie isolation...${NC}" +echo "Sending DEV cookies to LIVE deployment..." +DEV_COOKIES_ON_LIVE=$(curl -s -b /tmp/dev_cookies.txt "${LIVE_URL}/api/v1/debug/cookies" | grep -o "isolation-test-DEV") +echo "Sending LIVE cookies to DEV deployment..." +LIVE_COOKIES_ON_DEV=$(curl -s -b /tmp/live_cookies.txt "${DEV_URL}/api/v1/debug/cookies" | grep -o "isolation-test-LIVE") + +echo + +if [[ -z "$DEV_COOKIES_ON_LIVE" && -z "$LIVE_COOKIES_ON_DEV" ]]; then + echo -e "${GREEN}SUCCESS: Cookie isolation is working correctly!${NC}" + echo "The DEV cookies are not visible to the LIVE deployment, and vice versa." + echo "This means that sessions should be properly isolated." +else + echo -e "${RED}FAILURE: Cookie isolation is NOT working!${NC}" + + if [[ ! -z "$DEV_COOKIES_ON_LIVE" ]]; then + echo "- DEV cookies are visible to the LIVE deployment" + fi + + if [[ ! -z "$LIVE_COOKIES_ON_DEV" ]]; then + echo "- LIVE cookies are visible to the DEV deployment" + fi + + echo + echo "This means session contamination will occur between deployments." + echo "Please ensure each deployment has a unique cookie domain set with:" + echo " LEARNHOUSE_COOKIE_DOMAIN=adr-lms.whitex.cloud (for DEV)" + echo " LEARNHOUSE_COOKIE_DOMAIN=edu.adradviser.ro (for LIVE)" +fi + +echo +echo -e "${BLUE}Step 5: Checking domain and cookie settings...${NC}" +echo "DEV settings:" +curl -s "${DEV_URL}/api/v1/debug/deployment" | grep -E "cookie_domain|api_domain" | $JQ_CMD +echo +echo "LIVE settings:" +curl -s "${LIVE_URL}/api/v1/debug/deployment" | grep -E "cookie_domain|api_domain" | $JQ_CMD + +echo +echo -e "${BLUE}Cleaning up temporary files...${NC}" +rm -f /tmp/dev_cookies.txt /tmp/live_cookies.txt + +echo +echo "==============================================================" +echo "Test complete!" +echo "==============================================================" diff --git a/verify-all-isolation.sh b/verify-all-isolation.sh new file mode 100755 index 00000000..6fbbfc12 --- /dev/null +++ b/verify-all-isolation.sh @@ -0,0 +1,182 @@ +#!/bin/bash + +# Master Isolation Verification Script +# This script runs all isolation verification checks in sequence + +echo "====================================================================" +echo "LearnHouse Deployment Isolation - Complete Verification Suite" +echo "====================================================================" + +# Define colors for output +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Define the deployments +DEV_URL="http://adr-lms.whitex.cloud" +LIVE_URL="http://edu.adradviser.ro" + +# Function to check if a command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Check requirements +echo -e "${BLUE}Checking requirements...${NC}" +MISSING_TOOLS=0 + +if ! command_exists curl; then + echo -e "${RED}Missing required tool: curl${NC}" + MISSING_TOOLS=1 +fi + +if ! command_exists jq; then + echo -e "${YELLOW}Warning: jq is not installed. JSON output will not be formatted.${NC}" +fi + +if [ $MISSING_TOOLS -eq 1 ]; then + echo -e "${RED}Please install the missing tools and try again.${NC}" + exit 1 +fi + +echo -e "${GREEN}All required tools are available.${NC}" +echo + +# Function to run a verification script and report result +run_verification() { + script="$1" + description="$2" + + echo -e "${BLUE}Running: ${description}${NC}" + echo "--------------------------------------------------------------------" + + if [ -x "$script" ]; then + if "$script"; then + result=$? + if [ $result -eq 0 ]; then + echo -e "${GREEN}✓ PASSED: ${description}${NC}" + else + echo -e "${RED}✗ FAILED: ${description} (Exit code: $result)${NC}" + fi + else + echo -e "${RED}✗ ERROR: Failed to execute ${description}${NC}" + fi + else + echo -e "${RED}✗ ERROR: Script not found or not executable: ${script}${NC}" + fi + + echo "--------------------------------------------------------------------" + echo +} + +# Create output directory for reports +REPORT_DIR="/tmp/learnhouse-isolation-report" +mkdir -p "$REPORT_DIR" +echo -e "${BLUE}Reports will be saved in: ${REPORT_DIR}${NC}" +echo + +# Step 1: Run the enhanced deployment verification +echo -e "${BLUE}STEP 1: Testing basic deployment configuration${NC}" +curl -s "${DEV_URL}/api/v1/debug/deployment" > "${REPORT_DIR}/dev-deployment.json" +curl -s "${LIVE_URL}/api/v1/debug/deployment" > "${REPORT_DIR}/live-deployment.json" +run_verification "./verify-enhanced-isolation.sh" "Enhanced Deployment Verification" + +# Step 2: Test database isolation specifically +echo -e "${BLUE}STEP 2: Testing database isolation${NC}" +run_verification "./verify-db-isolation.sh" "Database Isolation Check" + +# Step 3: Test NextAuth cookie isolation +echo -e "${BLUE}STEP 3: Testing NextAuth cookies${NC}" +run_verification "./test-nextauth-cookie-isolation.sh" "NextAuth Cookie Isolation Test" + +# Step 4: Check for hardcoded URLs in the frontend +echo -e "${BLUE}STEP 4: Checking for hardcoded URLs${NC}" +echo "Checking DEV deployment for LIVE URLs..." +curl -s "${DEV_URL}/api/v1/debug/urls" > "${REPORT_DIR}/dev-urls.json" +DEV_HARDCODED_COUNT=$(grep -o "edu.adradviser.ro" "${REPORT_DIR}/dev-urls.json" | wc -l) + +echo "Checking LIVE deployment for DEV URLs..." +curl -s "${LIVE_URL}/api/v1/debug/urls" > "${REPORT_DIR}/live-urls.json" +LIVE_HARDCODED_COUNT=$(grep -o "adr-lms.whitex.cloud" "${REPORT_DIR}/live-urls.json" | wc -l) + +if [ $DEV_HARDCODED_COUNT -eq 0 ] && [ $LIVE_HARDCODED_COUNT -eq 0 ]; then + echo -e "${GREEN}✓ PASSED: No cross-deployment hardcoded URLs found${NC}" +else + echo -e "${RED}✗ FAILED: Found hardcoded URLs:${NC}" + if [ $DEV_HARDCODED_COUNT -gt 0 ]; then + echo " - DEV deployment contains ${DEV_HARDCODED_COUNT} references to LIVE domain" + fi + if [ $LIVE_HARDCODED_COUNT -gt 0 ]; then + echo " - LIVE deployment contains ${LIVE_HARDCODED_COUNT} references to DEV domain" + fi +fi +echo "--------------------------------------------------------------------" +echo + +# Step 5: Create the cookie isolation demo +echo -e "${BLUE}STEP 5: Creating cookie isolation demonstration tool${NC}" +run_verification "./create-cookie-demo.sh" "Cookie Isolation Demo Creation" + +# Summary of all tests +echo "====================================================================" +echo -e "${BLUE}SUMMARY OF ISOLATION VERIFICATION${NC}" +echo "====================================================================" + +# Check deployment names +DEV_NAME=$(grep -o '"deployment_name":"[^"]*"' "${REPORT_DIR}/dev-deployment.json" | cut -d'"' -f4) +LIVE_NAME=$(grep -o '"deployment_name":"[^"]*"' "${REPORT_DIR}/live-deployment.json" | cut -d'"' -f4) + +# Check database isolation +DEV_DB=$(grep -o '"name":"[^"]*"' "${REPORT_DIR}/dev-deployment.json" | head -1 | cut -d'"' -f4) +LIVE_DB=$(grep -o '"name":"[^"]*"' "${REPORT_DIR}/live-deployment.json" | head -1 | cut -d'"' -f4) + +# Check cookie domain isolation +DEV_COOKIE=$(grep -o '"cookie_domain":"[^"]*"' "${REPORT_DIR}/dev-deployment.json" | cut -d'"' -f4) +LIVE_COOKIE=$(grep -o '"cookie_domain":"[^"]*"' "${REPORT_DIR}/live-deployment.json" | cut -d'"' -f4) + +echo -e "Deployment Names:" +if [[ "$DEV_NAME" == "DEV" && "$LIVE_NAME" == "LIVE" ]]; then + echo -e " ${GREEN}✓ Correct: DEV='$DEV_NAME', LIVE='$LIVE_NAME'${NC}" +else + echo -e " ${RED}✗ Incorrect: DEV='$DEV_NAME', LIVE='$LIVE_NAME'${NC}" +fi + +echo -e "Database Isolation:" +if [[ "$DEV_DB" != "$LIVE_DB" && "$DEV_DB" != "unknown" && "$LIVE_DB" != "unknown" ]]; then + echo -e " ${GREEN}✓ Isolated: DEV='$DEV_DB', LIVE='$LIVE_DB'${NC}" +else + echo -e " ${RED}✗ Not isolated: DEV='$DEV_DB', LIVE='$LIVE_DB'${NC}" +fi + +echo -e "Cookie Domain Isolation:" +if [[ "$DEV_COOKIE" != "$LIVE_COOKIE" ]]; then + echo -e " ${GREEN}✓ Isolated: DEV='$DEV_COOKIE', LIVE='$LIVE_COOKIE'${NC}" +else + echo -e " ${RED}✗ Not isolated: DEV='$DEV_COOKIE', LIVE='$LIVE_COOKIE'${NC}" +fi + +echo -e "URL Hardcoding:" +if [ $DEV_HARDCODED_COUNT -eq 0 ] && [ $LIVE_HARDCODED_COUNT -eq 0 ]; then + echo -e " ${GREEN}✓ No cross-deployment hardcoded URLs${NC}" +else + echo -e " ${RED}✗ Found hardcoded URLs: DEV=$DEV_HARDCODED_COUNT, LIVE=$LIVE_HARDCODED_COUNT${NC}" +fi + +echo +echo "Report files saved to: ${REPORT_DIR}" +echo "====================================================================" + +# Final assessment +if [[ "$DEV_NAME" == "DEV" && "$LIVE_NAME" == "LIVE" && + "$DEV_DB" != "$LIVE_DB" && "$DEV_DB" != "unknown" && "$LIVE_DB" != "unknown" && + "$DEV_COOKIE" != "$LIVE_COOKIE" && + $DEV_HARDCODED_COUNT -eq 0 && $LIVE_HARDCODED_COUNT -eq 0 ]]; then + echo -e "${GREEN}OVERALL RESULT: PASSED - Deployments appear to be properly isolated!${NC}" + exit 0 +else + echo -e "${RED}OVERALL RESULT: FAILED - Deployment isolation issues detected!${NC}" + echo -e "Please refer to the ${BLUE}ISOLATION_IMPLEMENTATION_CHECKLIST.md${NC} to resolve these issues." + exit 1 +fi diff --git a/verify-enhanced-isolation.sh b/verify-enhanced-isolation.sh new file mode 100755 index 00000000..0a39908b --- /dev/null +++ b/verify-enhanced-isolation.sh @@ -0,0 +1,162 @@ +#!/bin/bash + +# Enhanced isolation verification script +# This script helps verify that the DEV and LIVE deployments are properly isolated + +echo "===================================================================================" +echo "LearnHouse Deployment Isolation Verification Tool" +echo "===================================================================================" + +# Define the URLs of both deployments +DEV_URL="http://adr-lms.whitex.cloud" +LIVE_URL="http://edu.adradviser.ro" + +# Colors for output +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to check if a command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Check if required tools are installed +if ! command_exists curl; then + echo -e "${RED}Error: curl is not installed. Please install curl and try again.${NC}" + exit 1 +fi + +if ! command_exists jq; then + echo -e "${YELLOW}Warning: jq is not installed. JSON responses will not be formatted nicely.${NC}" + JSON_PROCESSOR="cat" +else + JSON_PROCESSOR="jq" +fi + +echo -e "${BLUE}Checking deployment configurations...${NC}" +echo "" + +# Function to fetch deployment info +fetch_deployment_info() { + local url="$1" + local name="$2" + + echo -e "${BLUE}Checking ${name} deployment (${url})...${NC}" + echo "---------------------------------------------------------------------------------" + + # Make API call + response=$(curl -s "${url}/api/v1/debug/deployment" -H "Accept: application/json") + if [ $? -ne 0 ]; then + echo -e "${RED}Failed to connect to ${name} deployment.${NC}" + return 1 + fi + + # Display deployment info + echo -e "${GREEN}Deployment information:${NC}" + echo "$response" | $JSON_PROCESSOR + + # Extract key information + deployment_name=$(echo "$response" | grep -o '"deployment_name":"[^"]*"' | cut -d'"' -f4) + cookie_domain=$(echo "$response" | grep -o '"cookie_domain":"[^"]*"' | cut -d'"' -f4) + database_host=$(echo "$response" | grep -o '"host":"[^"]*"' | head -1 | cut -d'"' -f4) + database_name=$(echo "$response" | grep -o '"name":"[^"]*"' | head -1 | cut -d'"' -f4) + + echo "" + echo -e "${BLUE}Summary:${NC}" + echo "Deployment name: ${deployment_name:-unknown}" + echo "Cookie domain: ${cookie_domain:-unknown}" + echo "Database host: ${database_host:-unknown}" + echo "Database name: ${database_name:-unknown}" + echo "" + + # Check for cookie isolation + echo -e "${BLUE}Testing cookie isolation...${NC}" + cookie_response=$(curl -s "${url}/api/v1/debug/cookies" -H "Accept: application/json") + echo "$cookie_response" | $JSON_PROCESSOR + echo "" + + # Check for hardcoded URLs + echo -e "${BLUE}Checking for hardcoded URLs...${NC}" + url_response=$(curl -s "${url}/api/v1/debug/urls" -H "Accept: application/json") + + # Count hardcoded references to the other environment + other_url="" + if [[ "$url" == "$DEV_URL" ]]; then + other_url="edu.adradviser.ro" + else + other_url="adr-lms.whitex.cloud" + fi + + hardcoded_count=$(echo "$url_response" | grep -o "$other_url" | wc -l) + + if [[ $hardcoded_count -gt 0 ]]; then + echo -e "${RED}Warning: Found $hardcoded_count hardcoded references to $other_url${NC}" + echo "This could cause isolation issues!" + else + echo -e "${GREEN}No hardcoded references to the other environment found.${NC}" + fi + + # Check for session configuration + echo -e "${BLUE}Testing session configuration...${NC}" + session_response=$(curl -s "${url}/api/v1/debug/session" -H "Accept: application/json") + echo "$session_response" | $JSON_PROCESSOR + + echo "" + echo "---------------------------------------------------------------------------------" +} + +# Check both deployments +fetch_deployment_info "$DEV_URL" "DEV" +echo "" +fetch_deployment_info "$LIVE_URL" "LIVE" +echo "" + +echo -e "${BLUE}Analyzing isolation status...${NC}" +echo "---------------------------------------------------------------------------------" + +# Simple test: check if both deployments respond with the correct deployment name +dev_name=$(curl -s "${DEV_URL}/api/v1/debug/deployment" | grep -o '"deployment_name":"[^"]*"' | cut -d'"' -f4) +live_name=$(curl -s "${LIVE_URL}/api/v1/debug/deployment" | grep -o '"deployment_name":"[^"]*"' | cut -d'"' -f4) + +# Check database isolation +dev_db=$(curl -s "${DEV_URL}/api/v1/debug/deployment" | grep -o '"name":"[^"]*"' | head -1 | cut -d'"' -f4) +live_db=$(curl -s "${LIVE_URL}/api/v1/debug/deployment" | grep -o '"name":"[^"]*"' | head -1 | cut -d'"' -f4) + +# Check cookie domain isolation +dev_cookie=$(curl -s "${DEV_URL}/api/v1/debug/deployment" | grep -o '"cookie_domain":"[^"]*"' | cut -d'"' -f4) +live_cookie=$(curl -s "${LIVE_URL}/api/v1/debug/deployment" | grep -o '"cookie_domain":"[^"]*"' | cut -d'"' -f4) + +echo "SUMMARY OF ISOLATION STATUS:" +echo "" + +if [[ "$dev_name" == "DEV" && "$live_name" == "LIVE" ]]; then + echo -e "${GREEN}✓ Both deployments report the correct deployment name.${NC}" +else + echo -e "${RED}✗ Deployment name mismatch! DEV reports '$dev_name', LIVE reports '$live_name'${NC}" +fi + +if [[ "$dev_db" != "$live_db" ]]; then + echo -e "${GREEN}✓ Database isolation: Different database names ($dev_db vs $live_db)${NC}" +else + echo -e "${RED}✗ Database isolation failure! Both environments use the same database: $dev_db${NC}" +fi + +if [[ "$dev_cookie" != "$live_cookie" ]]; then + echo -e "${GREEN}✓ Cookie domain isolation: Different cookie domains ($dev_cookie vs $live_cookie)${NC}" +else + echo -e "${RED}✗ Cookie domain isolation failure! Both environments use the same cookie domain: $dev_cookie${NC}" +fi + +echo "" +echo "===================================================================================" + +if [[ "$dev_db" == "$live_db" || "$dev_cookie" == "$live_cookie" ]]; then + echo -e "${RED}Isolation verification FAILED! The deployments are not properly isolated.${NC}" + exit 1 +else + echo -e "${GREEN}Isolation verification PASSED! The deployments appear to be properly isolated.${NC}" + exit 0 +fi