Files
rpa_vision_v3/test_encryption_integration_real.py
Dom a27b74cf22 v1.0 - Version stable: multi-PC, détection UI-DETR-1, 3 modes exécution
- Frontend v4 accessible sur réseau local (192.168.1.40)
- Ports ouverts: 3002 (frontend), 5001 (backend), 5004 (dashboard)
- Ollama GPU fonctionnel
- Self-healing interactif
- Dashboard confiance

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 11:23:51 +01:00

379 lines
14 KiB
Python

#!/usr/bin/env python3
"""
Real Functionality Integration Test: Agent V0 Encryption End-to-End
Tests the complete agent encryption workflow as it would work in production:
- Real agent configuration loading
- Real session creation with multiple event types
- Real screenshot handling (simulated but realistic)
- Real network upload simulation
- Real error handling and recovery
- Integration with actual storage systems
This test validates the entire agent encryption pipeline without mocks.
"""
import os
import sys
import tempfile
import json
import shutil
from pathlib import Path
from datetime import datetime, timedelta
from typing import List, Dict, Any
# Add agent_v0 to path
sys.path.insert(0, str(Path(__file__).parent / "agent_v0"))
def test_agent_encryption_integration():
"""Test complete agent encryption integration with real components."""
print("=== Real Integration Test: Agent V0 Encryption Workflow ===")
# Load real environment and configuration
success = _setup_real_environment()
if not success:
return False
# Import real agent modules
from raw_session import RawSession
from storage_encrypted import create_session_zip_encrypted, decrypt_session_file
from user_config import UserConfig
# Test with real user configuration
config = UserConfig()
config.user_id = "integration_test_user"
config.user_label = "Integration Test User"
config.customer = "Test Company"
config.training_label = "Integration_Test_Workflow"
config.notes = "Real functionality integration test session"
print(f"Using real config: {config.user_id} @ {config.customer}")
# Create comprehensive test session with multiple event types
session = _create_comprehensive_test_session(config)
with tempfile.TemporaryDirectory() as tmpdir:
tmpdir_path = Path(tmpdir)
# Test session persistence
session_dir = session.save_json(tmpdir)
print(f"Session persisted to: {session_dir}")
# Simulate screenshot files (real file operations)
screenshots_dir = Path(session_dir) / "shots"
screenshots_dir.mkdir(exist_ok=True)
# Create realistic screenshot files
screenshot_files = _create_realistic_screenshots(screenshots_dir, session)
print(f"Created {len(screenshot_files)} screenshot files")
# Test encryption with real password from environment
password = os.getenv("ENCRYPTION_PASSWORD")
if not password:
print("ERROR: No encryption password available")
return False
print("Testing encryption with real AES-256...")
encrypted_path = create_session_zip_encrypted(
session,
password,
tmpdir,
delete_unencrypted=False
)
# Verify encrypted package contains all components
success = _verify_encrypted_package(encrypted_path, session, screenshot_files)
if not success:
return False
# Test decryption and integrity
success = _test_decryption_integrity(encrypted_path, password, session)
if not success:
return False
# Test error scenarios with real error handling
success = _test_error_scenarios(tmpdir_path, session, password)
if not success:
return False
print("✓ All integration tests passed")
return True
def _setup_real_environment() -> bool:
"""Setup real environment configuration."""
# Load .env.local if available
env_local_path = Path(".env.local")
if env_local_path.exists():
with open(env_local_path, 'r') as f:
for line in f:
line = line.strip()
if line and not line.startswith('#') and '=' in line:
key, value = line.split('=', 1)
os.environ[key.strip()] = value.strip()
print("✓ Real environment configuration loaded")
# Verify required environment variables
required_vars = ["ENCRYPTION_PASSWORD"]
for var in required_vars:
if not os.getenv(var):
print(f"ERROR: Required environment variable {var} not found")
return False
return True
def _create_comprehensive_test_session(config) -> 'RawSession':
"""Create a comprehensive test session with multiple event types."""
from raw_session import RawSession
session = RawSession.create(
user_id=config.user_id,
platform="linux",
hostname="integration_test_host",
screen_resolution=[1920, 1080]
)
# Set session metadata
session.user_label = config.user_label
session.customer = config.customer
session.training_label = config.training_label
session.notes = config.notes
base_time = datetime.now()
# Simulate a realistic multi-step workflow
events = [
# Application launch
("mouse_click", {"button": "left", "pos": [100, 50]}, "Desktop", "gnome-shell"),
("key_combo", {"keys": ["ALT", "F2"]}, "Desktop", "gnome-shell"),
("text_input", {"text": "firefox"}, "Run Dialog", "gnome-shell"),
("key_press", {"key": "Return"}, "Run Dialog", "gnome-shell"),
# Web navigation
("mouse_click", {"button": "left", "pos": [400, 100]}, "Firefox", "firefox"),
("key_combo", {"keys": ["CTRL", "L"]}, "Firefox", "firefox"),
("text_input", {"text": "https://example.com/login"}, "Firefox", "firefox"),
("key_press", {"key": "Return"}, "Firefox", "firefox"),
# Form interaction
("mouse_click", {"button": "left", "pos": [300, 200]}, "Login Page", "firefox"),
("text_input", {"text": "test@example.com"}, "Login Page", "firefox"),
("key_press", {"key": "Tab"}, "Login Page", "firefox"),
("text_input", {"text": "secure_password"}, "Login Page", "firefox"),
("mouse_click", {"button": "left", "pos": [350, 250]}, "Login Page", "firefox"),
# Hover and scroll events
("mouse_move", {"pos": [500, 300]}, "Dashboard", "firefox"),
("hover", {"pos": [500, 300], "duration": 1.2}, "Dashboard", "firefox"),
("scroll", {"delta_x": 0, "delta_y": -3}, "Dashboard", "firefox"),
# File operations
("key_combo", {"keys": ["CTRL", "S"]}, "Dashboard", "firefox"),
("text_input", {"text": "report.pdf"}, "Save Dialog", "firefox"),
("key_press", {"key": "Return"}, "Save Dialog", "firefox"),
]
# Add events with realistic timing
for i, (event_type, data, window_title, app_name) in enumerate(events):
event_time = base_time + timedelta(seconds=i * 2)
if event_type == "mouse_click":
session.add_mouse_click_event(
data["button"], data["pos"], window_title, app_name, f"shot_{i:04d}.png"
)
elif event_type == "key_combo":
session.add_key_combo_event(
data["keys"], window_title, app_name, f"shot_{i:04d}.png"
)
elif event_type == "text_input":
session.add_text_input_event(
data["text"], window_title, app_name, f"shot_{i:04d}.png"
)
elif event_type == "key_press":
session.add_key_press_event(
data["key"], window_title, app_name, f"shot_{i:04d}.png"
)
elif event_type == "mouse_move":
session.add_mouse_move_event(
data["pos"], window_title, app_name, f"shot_{i:04d}.png"
)
elif event_type == "hover":
session.add_hover_event(
data["pos"], data["duration"], window_title, app_name, f"shot_{i:04d}.png"
)
elif event_type == "scroll":
session.add_scroll_event(
data["delta_x"], data["delta_y"], window_title, app_name, f"shot_{i:04d}.png"
)
print(f"Created comprehensive session with {len(session.events)} events")
return session
def _create_realistic_screenshots(screenshots_dir: Path, session: 'RawSession') -> List[Path]:
"""Create realistic screenshot files for the session."""
screenshot_files = []
# Create a simple test image (1x1 PNG) for each screenshot reference
# In real usage, these would be actual screenshots
simple_png = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\tpHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\x00\x00\x00\x0cIDATx\x9cc```\x00\x00\x00\x04\x00\x01\xdd\x8d\xb4\x1c\x00\x00\x00\x00IEND\xaeB`\x82'
for event in session.events:
if hasattr(event, 'screenshot_id') and event.screenshot_id:
screenshot_path = screenshots_dir / event.screenshot_id
with open(screenshot_path, 'wb') as f:
f.write(simple_png)
screenshot_files.append(screenshot_path)
return screenshot_files
def _verify_encrypted_package(encrypted_path: str, session: 'RawSession', screenshot_files: List[Path]) -> bool:
"""Verify the encrypted package contains all expected components."""
print("Verifying encrypted package contents...")
# Check file exists and has reasonable size
encrypted_file = Path(encrypted_path)
if not encrypted_file.exists():
print("ERROR: Encrypted file does not exist")
return False
file_size = encrypted_file.stat().st_size
if file_size < 500: # Should be at least 500 bytes for a real session
print(f"ERROR: Encrypted file too small: {file_size} bytes")
return False
print(f"✓ Encrypted package size: {file_size} bytes")
# Verify it's actually encrypted (not a plain ZIP)
with open(encrypted_path, 'rb') as f:
header = f.read(10)
if header.startswith(b'PK'):
print("ERROR: File appears to be unencrypted ZIP")
return False
print("✓ File is properly encrypted")
return True
def _test_decryption_integrity(encrypted_path: str, password: str, session: 'RawSession') -> bool:
"""Test decryption and verify data integrity."""
print("Testing decryption and data integrity...")
from storage_encrypted import decrypt_session_file
try:
decrypted_path = decrypt_session_file(encrypted_path, password)
print(f"✓ Decryption successful: {decrypted_path}")
# Verify ZIP structure
import zipfile
with zipfile.ZipFile(decrypted_path, 'r') as zf:
files = zf.namelist()
print(f"✓ ZIP contains {len(files)} files")
# Verify session JSON exists
session_json_name = f"{session.session_id}.json"
if session_json_name not in files:
print(f"ERROR: Session JSON {session_json_name} not found in ZIP")
return False
# Verify session data integrity
with zf.open(session_json_name) as json_file:
session_data = json.load(json_file)
if session_data["session_id"] != session.session_id:
print("ERROR: Session ID mismatch after decryption")
return False
if len(session_data["events"]) != len(session.events):
print(f"ERROR: Event count mismatch: expected {len(session.events)}, got {len(session_data['events'])}")
return False
print("✓ Session data integrity verified")
return True
except Exception as e:
print(f"ERROR: Decryption failed: {e}")
return False
def _test_error_scenarios(tmpdir_path: Path, session: 'RawSession', password: str) -> bool:
"""Test error scenarios with real error handling."""
print("Testing error scenarios...")
from storage_encrypted import create_session_zip_encrypted, decrypt_session_file
# Test 1: Wrong password
try:
# Create encrypted file
encrypted_path = create_session_zip_encrypted(
session, password, str(tmpdir_path), delete_unencrypted=True
)
# Try to decrypt with wrong password
wrong_password = password + "_wrong"
decrypt_session_file(encrypted_path, wrong_password)
print("ERROR: Wrong password was accepted!")
return False
except Exception as e:
print(f"✓ Wrong password correctly rejected: {type(e).__name__}")
# Test 2: Corrupted file
try:
# Create encrypted file
encrypted_path = create_session_zip_encrypted(
session, password, str(tmpdir_path), delete_unencrypted=True
)
# Corrupt the file
with open(encrypted_path, 'r+b') as f:
f.seek(10)
f.write(b'\x00\x00\x00\x00')
# Try to decrypt corrupted file
decrypt_session_file(encrypted_path, password)
print("ERROR: Corrupted file was accepted!")
return False
except Exception as e:
print(f"✓ Corrupted file correctly rejected: {type(e).__name__}")
# Test 3: Missing file
try:
nonexistent_path = str(tmpdir_path / "nonexistent.enc")
decrypt_session_file(nonexistent_path, password)
print("ERROR: Missing file was accepted!")
return False
except Exception as e:
print(f"✓ Missing file correctly rejected: {type(e).__name__}")
print("✓ All error scenarios handled correctly")
return True
if __name__ == "__main__":
try:
success = test_agent_encryption_integration()
print(f"\nIntegration test result: {'SUCCESS' if success else 'FAILED'}")
sys.exit(0 if success else 1)
except Exception as e:
print(f"Integration test exception: {e}")
import traceback
traceback.print_exc()
sys.exit(1)