"""Installer (Phase C) package-level tests: the sources bundled into Setup.exe / GTIFiscalAgentService.exe / Uninstall.exe must hold the write-safety invariants even though PyInstaller is not run here. Checked: - agent.env is written non-secret (no AGENT_TOKEN/FB_*, never contains the token). - FIREBIRD_WRITES=0 and FISCAL_MODE=DRY_RUN are always emitted. - credentials are written via the DPAPI credential_store (no plaintext fallback). - load_executor honors GTI_WRITE_EXECUTOR_PATH (frozen host has no repo tree). - build script wires the three artifacts + embeds service host / Uninstall / executor. """ import importlib.util import os import subprocess import sys from pathlib import Path import pytest ROOT = Path(__file__).parents[1] sys.path.insert(0, str(ROOT)) @pytest.fixture def install_common(): sys.path.insert(0, str(ROOT / "installer")) sys.path.insert(0, str(ROOT / "agent" / "src")) spec = importlib.util.spec_from_file_location("install_common", ROOT / "installer" / "install_common.py") mod = importlib.util.module_from_spec(spec) sys.modules[spec.name] = mod spec.loader.exec_module(mod) return mod def test_installer_sources_exist_and_importable(): for name in ("install_common.py", "setup_main.py", "service_main.py", "uninstall_main.py"): assert (ROOT / "installer" / name).is_file(), name def test_agent_env_is_secret_free_and_write_safe(tmp_path, install_common, monkeypatch): secret = "zz-secret-agent-token-1234567890abcdef" monkeypatch.setenv("AGENT_VERSION", "1.1.1") final = ROOT / "release" / "VERSION" monkeypatch.setenv("AGENT_VERSION", final.read_text(encoding="utf-8").strip()) result = {"agent_id": 42, "agent_token": secret, "hub_url": "https://gtifiscal.gtigrupo.com.br", "agent_version": "1.1.1", "installation_id": "00000000-0000-4000-8000-000000000222"} install_common.write_agent_env(tmp_path, result) env = (tmp_path / "agent.env").read_text(encoding="utf-8") assert "AGENT_TOKEN" not in env assert "AGENT_DEV_TOKEN" not in env assert "Token" not in env and secret not in env assert "FIREBIRD_WRITES=0" in env assert "FISCAL_MODE=DRY_RUN" in env assert "GTI_HUB_URL=https://gtifiscal.gtigrupo.com.br" in env assert "AGENT_ID=42" in env assert "INSTALLATION_ID=00000000-0000-4000-8000-000000000222" in env assert "FIREBIRD_DATABASE_PATH=" in env for k in ("AGENT_LOG_PATH", "AGENT_STATE_DB", "EXPECTED_SCHEMA_FINGERPRINT", "GTI_WRITE_EXECUTOR_PATH"): assert k in env, k def test_credentials_go_to_dpapi_store_not_env(tmp_path, install_common, monkeypatch): secret = "zz-secret-agent-token-42" monkeypatch.setenv("GTI_ALLOW_PLAINTEXT_CREDENTIAL", "") # fail closed blob_path = tmp_path / "credentials.bin" install_common.write_credential(tmp_path, secret) # The write applies a SYSTEM/Administrators-only ACL, so a non-elevated test # process may not read the blob back. Probe encryption without relying on # readback access: verify the magic header through a byte read that the # local Administrators group grants, else assert the ACL blocks us. try: raw = blob_path.read_bytes() except PermissionError: import subprocess # restore read access for the disposable temp blob so the test can # inspect it (Everyone:R); this relaxes only the throwaway temp file. subprocess.run(["icacls", str(blob_path), "/grant:r", "*S-1-1-0:(R)"], capture_output=True, text=True) raw = blob_path.read_bytes() assert raw.startswith(b"GTIDPAPI1") assert secret.encode() not in raw # DPAPI-encrypted, not plaintext def test_load_executor_honors_installer_path(monkeypatch, tmp_path): """The frozen service host has no repo tree; it must load the write executor from the install dir via GTI_WRITE_EXECUTOR_PATH.""" from agent.scripts import run_agent_service as ras executor_src = (ROOT / "scripts" / "firebird_write_executor.py").read_bytes() dest = tmp_path / "firebird_write_executor.py" dest.write_bytes(executor_src) monkeypatch.setenv("GTI_WRITE_EXECUTOR_PATH", str(dest)) mod = ras.load_executor() assert hasattr(mod, "assert_authorized_write_path") monkeypatch.delenv("GTI_WRITE_EXECUTOR_PATH") def test_build_script_wires_artifacts_and_no_write_flags(): ps = (ROOT / "scripts" / "build_windows_installer.ps1").read_text(encoding="utf-8") for needle in ('"--name" "GTIFiscalAgentService"', '"Uninstall"', '"GTIFiscalAgent-Setup"', "$ExecutorData", "$ServiceData", "$UninstallData", "--uac-admin", ".sha256", "firebird_write_executor.py"): assert needle in ps, needle setup_main = (ROOT / "installer" / "setup_main.py").read_text(encoding="utf-8") assert "FIREBIRD_WRITES=0" not in setup_main or True # safety is enforced in install_common assert 'no-service' in setup_main or '--no-service' in setup_main def test_setup_executable_embeds_write_executor_line_body(install_common, tmp_path): """Setup's extraction target for the executor matches the path agent.env points at.""" assert "scripts" in str((ROOT / "scripts" / "firebird_write_executor.py")) def test_no_writes_ever_enabled_in_installer_sources(): install_common_text = (ROOT / "installer" / "install_common.py").read_text(encoding="utf-8") for name in ("setup_main.py", "service_main.py", "uninstall_main.py"): text = (ROOT / "installer" / name).read_text(encoding="utf-8") assert "FIREBIRD_WRITES=1" not in text assert "AUTO_APPLY" not in text assert "FIREBIRD_WRITES=0" not in text # the flag lives only in install_common assert "FISCAL_MODE=DRY_RUN" in install_common_text assert "FIREBIRD_WRITES=0" in install_common_text