"""Analyze the user's bounded manual attempt; never send authentication requests.""" import hashlib import json import re from pathlib import Path root = Path(__file__).resolve().parent.parent private = root / 'storage/app/private/investmoz-v2/portal-audit' file = private / 'auth-session-trace-qa.jsonl' all_rows = [json.loads(line) for line in file.read_text(encoding='utf-8').splitlines()] rows = [row for row in all_rows if '2026-10-09T21:22:00' <= row['at_utc'] <= '2026-10-09T21:24:59'] assert len(rows) == 6, 'Manual interval changed: inspect before classifying.' assert [(r['method'], r['path']) for r in rows] == [ ('GET', '/investimentos'), ('GET', '/login'), ('POST', '/login'), ('GET', '/two-factor-challenge'), ('POST', '/two-factor-challenge'), ('GET', '/login')] assert all(row['qa_target'] == 'desk_restore_20261009_174726_test:55441' for row in rows) login, challenge, mfa, next_request = rows[2:] assert login['after']['pending_mfa_user'] == challenge['loaded']['pending_mfa_user'] == mfa['loaded']['pending_mfa_user'] == 13 assert login['after']['session'] == challenge['loaded']['session'] == mfa['loaded']['session'] assert mfa['status'] == 302 and mfa['redirect']['path'] == '/login' assert all(not row['after']['authenticated_user'] for row in rows) assert next_request['loaded']['session'] == mfa['after']['session'] == next_request['loaded']['accepted_cookie_session'] # Export only the correlated structured warning; no arguments, headers or bodies. log = root / 'storage/logs/laravel.log' with log.open('rb') as f: f.seek(max(0, log.stat().st_size - 2 * 1024 * 1024)) lines = f.read().decode('utf-8', errors='replace').splitlines() warnings = [] for line in lines: match = re.match(r'^\[2026-10-09 21:23:04\] testing\.WARNING: Two-factor credential could not be decrypted; authentication refused\. (\{.*\})\s*$', line) if match: data = json.loads(match.group(1)) warnings.append({'at_utc': '2026-10-09T21:23:04+00:00', 'reference': data['reference'], 'pending_user_id': data['pending_user_id'], 'category': 'decryption_failure'}) snapshot_hash = hashlib.sha256(json.dumps(rows, sort_keys=True).encode()).hexdigest() archive = private / 'c37-manual-2122-2124-qa.json' if not warnings and archive.exists(): retained = json.loads(archive.read_text(encoding='utf-8')) assert retained['manual_trace_snapshot_sha256'] == snapshot_hash, 'Archived proof must match the same six requests.' warnings = [retained['warning']] assert len(warnings) == 1 and warnings[0]['pending_user_id'] == 13 diagnosis = json.loads((private / 'mfa-key-diagnosis-qa.json').read_text(encoding='utf-8-sig')) assert diagnosis['encrypted_field_checks']['two_factor_secret'] == {'qa': False, 'source_env': True} assert diagnosis['encrypted_field_checks']['two_factor_recovery_codes'] == {'qa': False, 'source_env': True} result = {'case': 'C37', 'manual_interval_utc': '2026-10-09 21:22:00–21:24:59', 'reported_expected_actor': 18, 'observed_challenged_actor': 13, 'mfa_screen_reached': True, 'manual_mfa_screen_observed_by_user': True, 'timeline': [{key: row[key] for key in ['at_utc', 'trace', 'method', 'path', 'status', 'redirect', 'loaded', 'after', 'persisted']} for row in rows], 'first_failure': {'at_utc': mfa['at_utc'], 'trace': mfa['trace'], 'path': mfa['path'], 'category': 'decryption_failure', 'result': 'Authentication refused before completion; controlled302 to /login and intentional session invalidation.'}, 'setup_mismatch_first_seen_at': login['at_utc'], 'warning': warnings[0], 'mfa_invalid_code_rejection': False, 'authentication_completed': False, 'session_lost_after_authentication': False, 'next_request_accepts_regenerated_session': True, 'cookie_conflict_observed': False, 'server_key_or_guard_changed': False, 'request_code_or_recovery_value_recorded': False, 'exact_mfa_input_mode_in_manual_trace': 'not recorded; no request bodies retained', 'cause_confirmed': True, 'cause': 'Restored non-synthetic account13 selected; its MFA credentials use the source key, incompatible with the stable isolated QA key. Account18 was not challenged in this attempt.', 'browser_acceptance_passed': False, 'active_writes': 0, 'manual_trace_snapshot_sha256': snapshot_hash} (private / 'c37-manual-2122-2124-qa.json').write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding='utf-8') (private / 'auth-session-diagnosis-qa.json').write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding='utf-8') print(json.dumps({key: value for key, value in result.items() if key != 'timeline'}, ensure_ascii=True, indent=2))