Files
GTI_GERENCIADOR_FISCAL/fiscal/tests/test_installer_artifacts.py
gti d21a9d1140 Add 'fiscal/' from commit '102ba84500dbd9655a0471288c3e278652593ca9'
git-subtree-dir: fiscal
git-subtree-mainline: d95165fc8f
git-subtree-split: 102ba84500
2026-09-29 14:43:23 -03:00

123 lines
5.7 KiB
Python

"""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