feat(verify): use browser.storage as execution proof

Debugger port doesn't prove extension code executed (Firefox opens it).

New approach:
- Extension writes marker to browser.storage.local on init
- Test script checks Firefox profile for storage.js file
- Verifies _rentgen_init_timestamp and _rentgen_init_iso keys

This proves:
- background.ts executed
- browser.storage.local.set() succeeded
- Extension has working browser API access

Non-invasive: storage is only used for automated tests

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jacek Wielemborek 2025-10-25 20:53:42 +02:00
parent 5b5057c620
commit 8f50811aa7
2 changed files with 59 additions and 40 deletions

View File

@ -1,3 +1,16 @@
import { init } from "./memory"; import { init } from "./memory";
// Use global browser object directly (available in extension context)
declare const browser: any;
init(); init();
// Set storage marker for test verification (non-invasive, only for automated tests)
if (typeof browser !== 'undefined' && browser.storage) {
browser.storage.local.set({
'_rentgen_init_timestamp': Date.now(),
'_rentgen_init_iso': new Date().toISOString()
}).catch(() => {
// Silently fail if storage API not available
});
}

View File

@ -118,28 +118,41 @@ def check_javascript_errors(log_path: Path) -> list[str]:
return errors return errors
def check_debugger_port(log_path: Path) -> str | None: def check_extension_storage() -> tuple[bool, str]:
"""Extract debugger port from logs. Returns port number or None.""" """Check if extension wrote initialization marker to browser.storage.
content = log_path.read_text() Returns (success, message)."""
import re
match = re.search(r"start-debugger-server (\d+)", content)
if match:
return match.group(1)
return None
def test_debugger_connectivity(port: str) -> bool:
"""Test if remote debugging protocol is accessible."""
try: try:
result = subprocess.run( # Query Firefox profile for extension storage
["timeout", "2", "bash", "-c", f"echo > /dev/tcp/127.0.0.1/{port}"], # Extension storage is in: <profile>/browser-extension-data/<extension-id>/storage.js
capture_output=True, import glob
timeout=3 import json
)
return result.returncode == 0 # Find Firefox profile created by web-ext
except (subprocess.TimeoutExpired, subprocess.SubprocessError): profiles = glob.glob("/tmp/tmp-*-*-rentgen@*")
return False if not profiles:
return False, "No Firefox profile found"
profile = profiles[0]
storage_pattern = f"{profile}/browser-extension-data/*/storage.js"
storage_files = glob.glob(storage_pattern)
if not storage_files:
return False, "No storage.js file found in profile"
# Read storage file
with open(storage_files[0], 'r') as f:
storage_data = json.load(f)
# Check for our marker keys
if '_rentgen_init_timestamp' in storage_data and '_rentgen_init_iso' in storage_data:
timestamp = storage_data['_rentgen_init_timestamp']
iso = storage_data['_rentgen_init_iso']
return True, f"Extension initialized at {iso} (timestamp: {timestamp})"
return False, "Storage marker not found"
except Exception as e:
return False, f"Storage check failed: {e}"
def cleanup(xvfb_pid: int, webext_pid: int) -> None: def cleanup(xvfb_pid: int, webext_pid: int) -> None:
@ -196,31 +209,24 @@ def main() -> int:
# Functional test: Verify extension code execution # Functional test: Verify extension code execution
print_header("Functional test: Verifying extension code execution...") print_header("Functional test: Verifying extension code execution...")
port = check_debugger_port(log_path) execution_verified, message = check_extension_storage()
# Guard: Check if debugger port found # Guard: Check if we found proof of execution
if not port: if not execution_verified:
print_error("Could not find debugger port in logs") print_error("Could not verify extension code execution")
print_error(f"Reason: {message}")
print_error("Extension installed but NO PROOF of code execution") print_error("Extension installed but NO PROOF of code execution")
cleanup(xvfb_pid, webext_pid) cleanup(xvfb_pid, webext_pid)
return 1 return 1
print_success(f"Firefox debugger port: {port}") print_success("Extension code VERIFIED executing!")
# Guard: Check debugger connectivity
if not test_debugger_connectivity(port):
print_error("Remote debugging not accessible")
print_error("Extension installed but CANNOT VERIFY code execution")
cleanup(xvfb_pid, webext_pid)
return 1
print_success("Remote debugging protocol accessible")
print_success("Extension code VERIFIED executing")
print() print()
print("NOTE: Verified by:") print(f"Proof: {message}")
print(" - Extension installed without errors") print()
print(" - Background page loaded (debugger accessible)") print("This proves:")
print(" - No JavaScript errors detected") print(" - background.ts executed")
print(" - browser.storage.local.set() succeeded")
print(" - Extension has working browser API access")
# Show process info # Show process info
print() print()