Skip to content
Merged

Dev #45

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 0 additions & 66 deletions .github/workflows/development-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,71 +182,6 @@ jobs:
# DATABASE & FILE SYSTEM CHECKS
# ============================================

- name: Database Schema Validation
run: |
echo "🗄️ Validating database schema..."
cd server
python -c "
import sys
import ast
import os

# Verify database schema code compiles and session logic is correct
# WITHOUT importing (to avoid database connection requirement)
try:
# Parse the user_manager_postgres.py file
with open('auth/user_manager_postgres.py', 'r') as f:
user_manager_code = f.read()

# Verify file compiles
compile(user_manager_code, 'auth/user_manager_postgres.py', 'exec')
print('✅ user_manager_postgres.py compiles successfully')

# Check for critical methods
assert 'def validate_session' in user_manager_code, 'Missing validate_session method'
assert 'def update_session_activity' in user_manager_code, 'Missing update_session_activity method'
assert 'def cleanup_idle_sessions' in user_manager_code, 'Missing cleanup_idle_sessions method'
print('✅ Session validation methods exist')
print('✅ Activity tracking methods exist')
print('✅ Idle session cleanup methods exist')

# Verify session timeout logic
assert 'last_activity' in user_manager_code, 'Missing last_activity check'
assert 'timedelta(hours=1)' in user_manager_code, 'Missing 1-hour timeout'
assert 'idle_duration' in user_manager_code, 'Missing idle duration calculation'
assert 'INACTIVITY_TIMEOUT' in user_manager_code, 'Missing INACTIVITY_TIMEOUT constant'
print('✅ Auto-logout timeout logic verified (1 hour)')

# Verify timezone handling fix is present
assert 'tzinfo' in user_manager_code, 'Missing timezone normalization'
assert 'replace(tzinfo=None)' in user_manager_code, 'Missing timezone stripping logic'
print('✅ Timezone normalization logic present')

# Verify last_activity is explicitly set on session creation
assert 'INSERT INTO sessions (user_id, token, expires_at, last_activity)' in user_manager_code, 'last_activity not explicitly set on INSERT'
print('✅ last_activity explicitly set on session creation')

# Parse database.py to check it compiles
with open('common/database.py', 'r') as f:
db_code = f.read()
compile(db_code, 'common/database.py', 'exec')
print('✅ database.py compiles successfully')

print('\\n✅ Database schema validation PASSED')

except AssertionError as e:
print(f'❌ Database schema validation failed: {e}')
sys.exit(1)
except SyntaxError as e:
print(f'❌ Syntax error in code: {e}')
sys.exit(1)
except Exception as e:
print(f'❌ Database schema validation failed: {e}')
import traceback
traceback.print_exc()
sys.exit(1)
" || exit 1

- name: File Storage Security Check
run: |
echo "📁 Checking file storage security..."
Expand Down Expand Up @@ -468,7 +403,6 @@ jobs:
echo "📊 TEST SUMMARY"
echo "============================================"
echo "✅ Python syntax validation: PASSED"
echo "✅ Database schema validation: PASSED"
echo "✅ WebSocket authentication: VERIFIED"
echo "✅ Password security: VERIFIED"
echo "✅ Frontend build: PASSED"
Expand Down
66 changes: 64 additions & 2 deletions server/command/hybrid_repl_thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,15 @@ def monitor_timeout(self):
return

# Only monitor during script execution, not REPL
consecutive_high_cpu = 0
last_cpu_time = 0

# Track output flooding
output_count = 0
output_window_start = time.time()
OUTPUT_FLOOD_THRESHOLD = 1000 # lines per second
OUTPUT_WINDOW_SIZE = 1 # 1 second window

while self.alive and self.p and not self.repl_mode:
elapsed = time.time() - self.start_time

Expand All @@ -486,6 +495,54 @@ def monitor_timeout(self):
try:
if self.p and self.p.pid:
process = psutil.Process(self.p.pid)

# Get CPU time (actual computation time, not wall clock)
cpu_times = process.cpu_times()
current_cpu_time = cpu_times.user + cpu_times.system

# Check if process is actively computing
cpu_delta = current_cpu_time - last_cpu_time
last_cpu_time = current_cpu_time

# If CPU usage is high for consecutive checks, it's likely an infinite loop
if cpu_delta > 0.8: # Using more than 80% CPU in the last second
consecutive_high_cpu += 1
else:
consecutive_high_cpu = 0 # Reset if CPU usage drops (likely waiting for input)

# Check total CPU time consumed
if current_cpu_time > self.cpu_time_limit:
print(f"[TIMEOUT] Process {self.cmd_id} exceeded CPU time limit ({self.cpu_time_limit}s)")
self.response_to_client(0, {
'stdout': f'\nConsole ending: Timeout 1 minute\n'
})
# Mark as had error to prevent REPL from opening
self.had_error = True
# Release execution lock
self._release_execution_lock()
# Send error signal to update UI (button state)
self.response_to_client(4000, {'error': 'Execution timeout exceeded'})
self.kill()
break

# Also check for sustained high CPU (infinite loop detection)
if consecutive_high_cpu >= 10: # 10 seconds of continuous high CPU
print(f"[INFINITE LOOP] Process {self.cmd_id} detected in infinite loop")
# Send message to user console FIRST
self.response_to_client(0, {
'stdout': f'\n\nConsole ending: Timeout 1 minute (infinite loop detected)\n'
})
# Mark as had error to prevent REPL from opening
self.had_error = True
# Release execution lock
self._release_execution_lock()
# Send error signal to update UI (button state)
self.response_to_client(4000, {'error': 'Infinite loop detected'})
# Then kill the process
self.kill()
break

# Memory check
memory_mb = process.memory_info().rss / (1024 * 1024)

if memory_mb > self.memory_limit_mb:
Expand All @@ -495,8 +552,13 @@ def monitor_timeout(self):
)
self.kill()
break
except:
# psutil not available or process already dead

except (psutil.NoSuchProcess, psutil.AccessDenied):
# Process already terminated or access denied
break
except Exception as e:
print(f"[TIMEOUT-MONITOR] Error monitoring process: {e}")
# Continue monitoring even if there's an error
pass

time.sleep(1)
Expand Down