"""Software-only tests for the authenticated bootstrap package.""" from __future__ import annotations import hashlib import json import os from pathlib import Path from pathlib import PurePosixPath import shutil import subprocess import unicodedata import zipfile import pytest import tools.rf001_build_agent_packages as packages from tools.rf001_agent_update import ( RELEASE_SOURCE_FILES, ReleaseValidationError, source_agent_version, ) def _bootstrap_source( root: Path, *, agent_version: str = "2026.09.29.1", ) -> Path: fixed = { "INSTALL_RX_AGENT.cmd": "@echo off\n", "UNINSTALL_RX_AGENT.cmd": "@echo off\n", "tools/rf001_bootstrap_readme.txt": "fixed bootstrap readme\n", "tools/rf001_agent_launcher.py": "# fixed launcher\n", "tools/install_rf001_rx_autostart.ps1": "# fixed installer\n", "tools/uninstall_rf001_rx_autostart.ps1": "# fixed uninstaller\n", } for name, content in fixed.items(): path = root / name path.parent.mkdir(parents=True, exist_ok=True) path.write_text(content, encoding="utf-8") for index, relative in enumerate(RELEASE_SOURCE_FILES.values()): path = root / relative path.parent.mkdir(parents=True, exist_ok=True) content = f"# fixed release source {index}\n" if relative == RELEASE_SOURCE_FILES["app/tools/rf001_rx_http_agent.py"]: content += f'AGENT_VERSION = "{agent_version}"\n' path.write_text(content, encoding="utf-8") reference = root / ".local/rf001_probe/lab065_reference_staircase.cs8" reference.parent.mkdir(parents=True, exist_ok=True) reference.write_bytes(b"fixed exact staircase fixture") return reference def _formed_installer_allowlist(release_id: str) -> list[str]: powershell = shutil.which("powershell.exe") if powershell is None: pytest.skip("Windows PowerShell is required to evaluate the installer allowlist") installer = Path(packages.__file__).with_name("install_rf001_rx_autostart.ps1") environment = os.environ.copy() environment["SDR_ROVER_INSTALLER_PATH"] = str(installer) environment["SDR_ROVER_RELEASE_ID"] = release_id command = r""" $ErrorActionPreference = "Stop" $tokens = $null $parseErrors = $null $syntax = [Management.Automation.Language.Parser]::ParseFile( $env:SDR_ROVER_INSTALLER_PATH, [ref]$tokens, [ref]$parseErrors ) if ($parseErrors.Count -ne 0) { throw "Installer contains PowerShell parse errors" } $assignments = @($syntax.FindAll({ param($node) $node -is [Management.Automation.Language.AssignmentStatementAst] -and $node.Left -is [Management.Automation.Language.VariableExpressionAst] -and $node.Left.VariablePath.UserPath -eq "expectedPaths" }, $true)) if ($assignments.Count -ne 1) { throw "Installer expectedPaths assignment is absent or ambiguous" } $releasePrefix = "versions/$($env:SDR_ROVER_RELEASE_ID)/" . ([scriptblock]::Create($assignments[0].Extent.Text)) ConvertTo-Json -Compress -InputObject @($expectedPaths) """ completed = subprocess.run( [powershell, "-NoProfile", "-NonInteractive", "-Command", command], check=True, capture_output=True, encoding="utf-8", env=environment, ) value = json.loads(completed.stdout.lstrip("\ufeff")) assert isinstance(value, list) assert all(isinstance(path, str) for path in value) return value def test_bootstrap_is_authenticated_and_excludes_secret( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: source = tmp_path / "source" reference = _bootstrap_source(source) monkeypatch.setattr( packages, "REFERENCE_SHA256", hashlib.sha256(reference.read_bytes()).hexdigest(), ) token = tmp_path / "token.txt" token.write_text("fixed-test-token-0123456789abcdef", encoding="utf-8") package = tmp_path / "bootstrap.zip" built = packages.build_bootstrap_archive( source, package, bootstrap_id="rf001-bootstrap-2026.09.29.1", agent_release_id="rf001-agent-2026.09.29.1", agent_version="2026.09.29.1", protocol_version=1, token_path=token, ) checked = packages.inspect_bootstrap_archive(package, token_path=token) assert checked == built assert checked.file_count == len(RELEASE_SOURCE_FILES) + 8 with zipfile.ZipFile(package) as archive: names = archive.namelist() manifest = json.loads(archive.read(packages.BOOTSTRAP_MANIFEST_NAME)) ready = json.loads( archive.read("versions/rf001-agent-2026.09.29.1/READY.json") ) assert not any("token" in name.casefold() for name in names) assert not any( b"fixed-test-token" in archive.read(name) for name in names ) actual_version = source_agent_version( source / RELEASE_SOURCE_FILES["app/tools/rf001_rx_http_agent.py"] ) assert manifest["agent_version"] == actual_version assert ready["agent_version"] == actual_version def test_new_bootstrap_preserves_existing_release_bytes( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: source = tmp_path / "source" reference = _bootstrap_source(source) monkeypatch.setattr( packages, "REFERENCE_SHA256", hashlib.sha256(reference.read_bytes()).hexdigest(), ) token = tmp_path / "token.txt" token.write_text("fixed-test-token-0123456789abcdef", encoding="utf-8") base_package = tmp_path / "bootstrap-4.zip" next_package = tmp_path / "bootstrap-5.zip" release_id = "rf001-agent-2026.09.29.1" packages.build_bootstrap_archive( source, base_package, bootstrap_id="rf001-bootstrap-2026.09.29.4", agent_release_id=release_id, agent_version="2026.09.29.1", protocol_version=1, token_path=token, ) (source / "tools/rf001_agent_launcher.py").write_text( "# corrected launcher\n", encoding="utf-8", ) packages.build_bootstrap_archive( source, next_package, bootstrap_id="rf001-bootstrap-2026.09.29.5", agent_release_id=release_id, agent_version="2026.09.29.1", protocol_version=1, token_path=token, agent_release_bootstrap_id="rf001-bootstrap-2026.09.29.4", ) release_prefix = f"versions/{release_id}/" with zipfile.ZipFile(base_package) as base, zipfile.ZipFile(next_package) as new: release_names = sorted( name for name in base.namelist() if name.startswith(release_prefix) ) assert release_names assert all(base.read(name) == new.read(name) for name in release_names) assert base.read("launcher/rf001_agent_launcher.py") != new.read( "launcher/rf001_agent_launcher.py" ) manifest = json.loads(new.read(packages.BOOTSTRAP_MANIFEST_NAME)) ready = json.loads(new.read(f"{release_prefix}READY.json")) assert manifest["bootstrap_id"] == "rf001-bootstrap-2026.09.29.5" assert ( manifest["agent_release_bootstrap_id"] == "rf001-bootstrap-2026.09.29.4" ) assert ready["bootstrap_id"] == "rf001-bootstrap-2026.09.29.4" def test_bootstrap_rejects_the_wrong_existing_secret( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: source = tmp_path / "source" reference = _bootstrap_source(source) monkeypatch.setattr( packages, "REFERENCE_SHA256", hashlib.sha256(reference.read_bytes()).hexdigest(), ) token = tmp_path / "token.txt" token.write_text("fixed-test-token-0123456789abcdef", encoding="utf-8") package = tmp_path / "bootstrap.zip" packages.build_bootstrap_archive( source, package, bootstrap_id="rf001-bootstrap-2026.09.29.1", agent_release_id="rf001-agent-2026.09.29.1", agent_version="2026.09.29.1", protocol_version=1, token_path=token, ) wrong = tmp_path / "wrong.txt" wrong.write_text("another-fixed-token-0123456789abcdef", encoding="utf-8") with pytest.raises(ValueError, match="signature mismatch"): packages.inspect_bootstrap_archive(package, token_path=wrong) def test_installer_allowlist_matches_signed_manifest_and_has_safe_paths( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: source = tmp_path / "source" reference = _bootstrap_source(source) monkeypatch.setattr( packages, "REFERENCE_SHA256", hashlib.sha256(reference.read_bytes()).hexdigest(), ) token = tmp_path / "token.txt" token.write_text("fixed-test-token-0123456789abcdef", encoding="utf-8") package = tmp_path / "bootstrap.zip" release_id = "rf001-agent-2026.09.29.1" packages.build_bootstrap_archive( source, package, bootstrap_id="rf001-bootstrap-2026.09.29.2", agent_release_id=release_id, agent_version="2026.09.29.1", protocol_version=1, token_path=token, ) with zipfile.ZipFile(package) as archive: manifest = json.loads(archive.read(packages.BOOTSTRAP_MANIFEST_NAME)) manifest_paths = {row["path"] for row in manifest["files"]} formed_paths = _formed_installer_allowlist(release_id) assert set(formed_paths) == manifest_paths assert len(formed_paths) == len(manifest_paths) assert f"versions/{release_id}/READY.json" in formed_paths assert ( f"versions/{release_id}/app/tools/hackrf_process_check.py" in formed_paths ) assert ( f"versions/{release_id}/app/tools/rf001_staircase_search.py" in formed_paths ) for path in formed_paths: assert not any(unicodedata.category(character) == "Cc" for character in path) parsed = PurePosixPath(path) assert not parsed.is_absolute() assert all(part not in ("", ".", "..") for part in parsed.parts) assert "\\" not in path assert not any(":" in part for part in parsed.parts) with zipfile.ZipFile(package, "a") as archive: archive.writestr("unexpected/extra.txt", b"prohibited") with pytest.raises(ValueError, match="unexpected files"): packages.inspect_bootstrap_archive(package, token_path=token) @pytest.mark.parametrize( ("source_version", "requested_version"), ( ("2026.09.29.2", "2026.09.29.1"), ("2026.09.29.1", "2026.09.29.2"), ), ) def test_bootstrap_rejects_agent_version_mismatch_before_creating_artifact( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, source_version: str, requested_version: str, ) -> None: source = tmp_path / "source" reference = _bootstrap_source(source, agent_version=source_version) monkeypatch.setattr( packages, "REFERENCE_SHA256", hashlib.sha256(reference.read_bytes()).hexdigest(), ) token = tmp_path / "token.txt" token.write_text("fixed-test-token-0123456789abcdef", encoding="utf-8") package = tmp_path / "must-not-exist.zip" with pytest.raises(ReleaseValidationError, match="AGENT_VERSION|release_id"): packages.build_bootstrap_archive( source, package, bootstrap_id="rf001-bootstrap-2026.09.29.3", agent_release_id=f"rf001-agent-{requested_version}", agent_version=requested_version, protocol_version=1, token_path=token, ) assert not package.exists()