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>
This commit is contained in:
261
test_fresh_encryption.py
Normal file
261
test_fresh_encryption.py
Normal file
@@ -0,0 +1,261 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Real Functionality Test: Fresh Encryption Cycle
|
||||
|
||||
Tests the complete encryption/decryption workflow using:
|
||||
- Real RawSession data with actual events
|
||||
- Real file system operations
|
||||
- Real encryption algorithms (AES-256)
|
||||
- Real ZIP file creation and validation
|
||||
- Actual environment variable loading
|
||||
|
||||
This test validates the entire encryption pipeline as it would work in production.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import json
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
# Add agent_v0 to path
|
||||
sys.path.insert(0, str(Path(__file__).parent / "agent_v0"))
|
||||
|
||||
def test_fresh_encryption():
|
||||
"""Test complete encryption cycle with real data and operations."""
|
||||
|
||||
print("=== Real Functionality Test: Fresh Encryption Cycle ===")
|
||||
|
||||
# Load real environment configuration
|
||||
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()
|
||||
|
||||
password = os.getenv("ENCRYPTION_PASSWORD")
|
||||
if not password:
|
||||
print("ERROR: ENCRYPTION_PASSWORD not found in environment")
|
||||
return False
|
||||
|
||||
print(f"Using encryption password: {password[:4]}{'*' * (len(password) - 4)}")
|
||||
|
||||
# Import real agent modules (no mocks)
|
||||
from raw_session import RawSession
|
||||
from storage_encrypted import create_session_zip_encrypted, decrypt_session_file
|
||||
|
||||
# Create realistic test session with actual user interaction data
|
||||
session = RawSession.create(
|
||||
user_id="test_encryption_user",
|
||||
platform="linux",
|
||||
hostname="test_workstation",
|
||||
screen_resolution=[1920, 1080]
|
||||
)
|
||||
|
||||
# Add realistic interaction events (simulating real user actions)
|
||||
base_time = datetime.now()
|
||||
|
||||
# Simulate a realistic workflow: login sequence
|
||||
session.add_mouse_click_event("left", [450, 320], "Login Form", "firefox", None)
|
||||
session.add_key_combo_event(["CTRL", "A"], "Login Form", "firefox", None)
|
||||
session.add_text_input_event("user@example.com", "Login Form", "firefox", None)
|
||||
session.add_key_press_event("Tab", "Login Form", "firefox", None)
|
||||
session.add_text_input_event("password123", "Login Form", "firefox", None)
|
||||
session.add_mouse_click_event("left", [500, 400], "Login Form", "firefox", None)
|
||||
|
||||
print(f"Created realistic session: {session.session_id}")
|
||||
print(f"Session contains {len(session.events)} interaction events")
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
tmpdir_path = Path(tmpdir)
|
||||
|
||||
# Save session using real file operations
|
||||
session_dir = session.save_json(tmpdir)
|
||||
print(f"Session saved to: {session_dir}")
|
||||
|
||||
# Verify session files exist and are valid
|
||||
session_json_path = Path(session_dir) / f"{session.session_id}.json"
|
||||
assert session_json_path.exists(), "Session JSON file not created"
|
||||
|
||||
# Validate JSON content
|
||||
with open(session_json_path, 'r') as f:
|
||||
session_data = json.load(f)
|
||||
assert session_data["session_id"] == session.session_id
|
||||
assert len(session_data["events"]) == 6
|
||||
print("✓ Session JSON validation passed")
|
||||
|
||||
# Test encryption with real AES-256 encryption
|
||||
print("Encrypting session with real AES-256...")
|
||||
encrypted_path = create_session_zip_encrypted(
|
||||
session,
|
||||
password,
|
||||
tmpdir,
|
||||
delete_unencrypted=False # Keep for verification
|
||||
)
|
||||
|
||||
print(f"Encrypted file created: {encrypted_path}")
|
||||
|
||||
# Verify encrypted file properties
|
||||
encrypted_file = Path(encrypted_path)
|
||||
assert encrypted_file.exists(), "Encrypted file not created"
|
||||
|
||||
file_size = encrypted_file.stat().st_size
|
||||
print(f"Encrypted file size: {file_size} bytes")
|
||||
assert file_size > 100, "Encrypted file suspiciously small"
|
||||
|
||||
# Verify file is actually encrypted (not plain ZIP)
|
||||
with open(encrypted_path, 'rb') as f:
|
||||
header = f.read(4)
|
||||
# Should NOT be a standard ZIP header (PK\x03\x04)
|
||||
assert header != b'PK\x03\x04', "File appears to be unencrypted ZIP"
|
||||
print("✓ File is properly encrypted (not plain ZIP)")
|
||||
|
||||
# Test decryption with real decryption algorithm
|
||||
print("Testing decryption with real algorithm...")
|
||||
try:
|
||||
decrypted_path = decrypt_session_file(encrypted_path, password)
|
||||
print(f"SUCCESS: Decrypted to {decrypted_path}")
|
||||
|
||||
# Verify decrypted file is valid ZIP
|
||||
import zipfile
|
||||
with zipfile.ZipFile(decrypted_path, 'r') as zf:
|
||||
files = zf.namelist()
|
||||
print(f"Decrypted ZIP contains {len(files)} files: {files}")
|
||||
|
||||
# Verify session JSON is in the ZIP
|
||||
session_json_name = f"{session.session_id}.json"
|
||||
assert session_json_name in files, f"Session JSON {session_json_name} not found in ZIP"
|
||||
|
||||
# Extract and validate session content
|
||||
with zf.open(session_json_name) as json_file:
|
||||
decrypted_session_data = json.load(json_file)
|
||||
assert decrypted_session_data["session_id"] == session.session_id
|
||||
assert len(decrypted_session_data["events"]) == 6
|
||||
print("✓ Decrypted session data validation passed")
|
||||
|
||||
# Test wrong password fails appropriately
|
||||
print("Testing wrong password rejection...")
|
||||
try:
|
||||
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 file integrity with checksum
|
||||
original_checksum = _calculate_file_checksum(session_json_path)
|
||||
|
||||
# Extract decrypted session for comparison
|
||||
with zipfile.ZipFile(decrypted_path, 'r') as zf:
|
||||
with zf.open(session_json_name) as json_file:
|
||||
decrypted_content = json_file.read()
|
||||
|
||||
temp_extracted = tmpdir_path / "extracted_session.json"
|
||||
with open(temp_extracted, 'wb') as f:
|
||||
f.write(decrypted_content)
|
||||
|
||||
decrypted_checksum = _calculate_file_checksum(temp_extracted)
|
||||
|
||||
if original_checksum == decrypted_checksum:
|
||||
print("✓ File integrity verified: checksums match")
|
||||
else:
|
||||
print(f"WARNING: Checksum mismatch - original: {original_checksum}, decrypted: {decrypted_checksum}")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"FAILED: Decryption error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
|
||||
def _calculate_file_checksum(file_path: Path) -> str:
|
||||
"""Calculate SHA-256 checksum of a file for integrity verification."""
|
||||
sha256_hash = hashlib.sha256()
|
||||
with open(file_path, "rb") as f:
|
||||
for chunk in iter(lambda: f.read(4096), b""):
|
||||
sha256_hash.update(chunk)
|
||||
return sha256_hash.hexdigest()
|
||||
|
||||
|
||||
def test_encryption_performance():
|
||||
"""Test encryption performance with realistic data sizes."""
|
||||
print("\n=== Performance Test: Encryption Speed ===")
|
||||
|
||||
password = os.getenv("ENCRYPTION_PASSWORD", "test_password_123")
|
||||
|
||||
# Import real modules
|
||||
from raw_session import RawSession
|
||||
from storage_encrypted import create_session_zip_encrypted
|
||||
|
||||
# Create larger session for performance testing
|
||||
session = RawSession.create(
|
||||
user_id="perf_test_user",
|
||||
platform="linux",
|
||||
hostname="perf_test",
|
||||
screen_resolution=[2560, 1440]
|
||||
)
|
||||
|
||||
# Add many events to test with realistic data size
|
||||
base_time = datetime.now()
|
||||
for i in range(100): # 100 events
|
||||
session.add_mouse_move_event([100 + i, 200 + i], f"App {i}", "test_app", None)
|
||||
|
||||
print(f"Created performance test session with {len(session.events)} events")
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
session.save_json(tmpdir)
|
||||
|
||||
# Measure encryption time
|
||||
import time
|
||||
start_time = time.time()
|
||||
|
||||
encrypted_path = create_session_zip_encrypted(
|
||||
session,
|
||||
password,
|
||||
tmpdir,
|
||||
delete_unencrypted=True
|
||||
)
|
||||
|
||||
encryption_time = time.time() - start_time
|
||||
file_size = Path(encrypted_path).stat().st_size
|
||||
|
||||
print(f"Encryption completed in {encryption_time:.3f} seconds")
|
||||
print(f"Encrypted file size: {file_size} bytes")
|
||||
print(f"Encryption speed: {file_size / encryption_time / 1024:.1f} KB/s")
|
||||
|
||||
# Performance should be reasonable (>100 KB/s)
|
||||
speed_kbps = file_size / encryption_time / 1024
|
||||
if speed_kbps > 100:
|
||||
print("✓ Encryption performance acceptable")
|
||||
return True
|
||||
else:
|
||||
print(f"WARNING: Encryption performance slow: {speed_kbps:.1f} KB/s")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
# Run main encryption test
|
||||
success1 = test_fresh_encryption()
|
||||
|
||||
# Run performance test
|
||||
success2 = test_encryption_performance()
|
||||
|
||||
overall_success = success1 and success2
|
||||
print(f"\nOverall test result: {'SUCCESS' if overall_success else 'FAILED'}")
|
||||
print(f"- Encryption cycle: {'PASS' if success1 else 'FAIL'}")
|
||||
print(f"- Performance test: {'PASS' if success2 else 'FAIL'}")
|
||||
|
||||
sys.exit(0 if overall_success else 1)
|
||||
except Exception as e:
|
||||
print(f"Test exception: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user