from __future__ import annotations import json import zipfile from pathlib import Path from boltclam import paths from boltclam.config import SettingsStore from boltclam.logging_setup import redact from boltclam.logs import build_bundle, redact_paths, sanitize_text, upload_bundle from boltclam.models import ClamAVInfo, Detection from boltclam.storage import Storage from boltclam.system_info import collect def test_redaction_covers_tokens_and_emails(): text = "key=bolt_live_abcdef password=hunter2 user aaron@example.com" redacted = sanitize_text(text) assert "bolt_live_abcdef" not in redacted assert "hunter2" not in redacted assert "aaron@example.com" not in redacted assert "[email]" in redacted or "[redacted]" in redacted def test_path_redaction_uses_userprofile(isolated_env): sample = str(Path.home() / "Downloads" / "bad.exe") assert "%USERPROFILE%" in redact_paths(sample) assert "Downloads" in redact_paths(sample) def test_bundle_contains_redacted_logs_and_scan_summary(isolated_env): settings = SettingsStore().load() storage = Storage() scan_id = storage.create_scan("homes", [str(Path.home() / "Downloads")]) detection = Detection(path=str(Path.home() / "Downloads" / "bad.exe"), signature="Win.Test", size=10) detection.id = storage.add_detection(scan_id, detection) storage.finish_scan(scan_id, status="completed", scanned_files=10, infected_files=1, errors=0, duration_seconds=2, cancelled=False) paths.logs_dir().mkdir(parents=True, exist_ok=True) (paths.logs_dir() / "boltclam.log").write_text( f"token=bolt_live_supersecret user aaron@example.com path={Path.home()}/x\n", encoding="utf-8") info = ClamAVInfo(available=True, path=Path("/fake/clamscan"), engine_version="1.4.3", db_version="27452", db_path=Path("/fake/db"), db_date="2026-10-22", db_age_days=1.0) snapshot = collect(settings, info, storage, realtime_running=False, force=True) bundle = build_bundle(settings, info, system_snapshot=snapshot, account={"user": {"email": "aaron@example.com"}}, realtime_roots=[str(Path.home() / "Downloads")]) assert bundle.is_file() with zipfile.ZipFile(bundle) as archive: names = set(archive.namelist()) assert {"manifest.json", "boltclam-logs.txt", "system-summary.json", "README.txt"} <= names logs = archive.read("boltclam-logs.txt").decode() assert "bolt_live_supersecret" not in logs assert "aaron@example.com" not in logs assert "%USERPROFILE%" in logs manifest = json.loads(archive.read("manifest.json")) assert manifest["app"] == "BoltClam" assert manifest["account"]["email"] == "aaron@example.com" summary = json.loads(archive.read("system-summary.json")) assert summary["stats"]["latest_scan"]["id"] == scan_id class FakeApi: def upload_diagnostics(self, path, metadata=None): return {"id": "42/test.zip", "bytes": Path(path).stat().st_size} def test_upload_bundle_returns_server_id(isolated_env): settings = SettingsStore().load() storage = Storage() info = ClamAVInfo(available=False, error="not installed") bundle = build_bundle(settings, info) result = upload_bundle(FakeApi(), bundle, settings) assert result["id"] == "42/test.zip"