Files
GTI_GERENCIADOR_FISCAL/tests/test_release_candidate.py
T

108 lines
6.5 KiB
Python

import importlib.util
import json
import re
import sys
import zipfile
from pathlib import Path
import pytest
ROOT = Path(__file__).parents[1]
sys.path.insert(0, str(ROOT))
def test_versions_are_coherent_across_hub_and_packages():
"""GTI_FISCAL_VERSION is the Hub's own single source (release/VERSION, central/app/version.py,
central/pyproject.toml, the manifest). It is deliberately NOT required to match the Agent's own
version (see test_agent_version_is_internally_coherent below) - a Hub-only release (Missão 2/3)
must be able to bump this without touching, rebuilding or republishing the Agent at all."""
from central.app.version import GTI_FISCAL_VERSION
v = (ROOT / "release" / "VERSION").read_text(encoding="utf-8").strip()
assert v == GTI_FISCAL_VERSION == "1.3.13"
pep = v.replace("-rc", "rc")
assert f'version = "{pep}"' in (ROOT / "central" / "pyproject.toml").read_text(encoding="utf-8")
manifest = ROOT / "release" / "RELEASE_MANIFEST.json"
if manifest.exists():
m = json.loads(manifest.read_text(encoding="utf-8"))
assert m["GTI_FISCAL_VERSION"] == v and m["migrations"]["alembic_head_in_repo"] == m["migrations"]["applied_revision"]
def test_agent_version_is_internally_coherent():
"""The Agent's own version references must agree with EACH OTHER (never guessed, never silently
drifting), but are an independent number from the Hub's GTI_FISCAL_VERSION - the Agent is only
ever re-versioned when its own code/behavior changes and a new installer is actually built."""
agent_pep = (ROOT / "agent" / "pyproject.toml").read_text(encoding="utf-8")
m = re.search(r'version = "([^"]+)"', agent_pep)
assert m, "agent/pyproject.toml must declare a version"
agent_version = m.group(1)
assert f'"AGENT_VERSION", "{agent_version}"' in (ROOT / "agent" / "scripts" / "run_agent_service.py").read_text(encoding="utf-8")
assert f'AGENT_VERSION_DEFAULT = "{agent_version}"' in (ROOT / "agent" / "src" / "gti_fiscal_agent" / "preflight.py").read_text(encoding="utf-8")
def test_manifest_records_the_real_migration_head():
# The manifest said "0011" while the repository was already at 0018: the
# generator used the 4-digit file prefix and nothing compared it to Alembic.
from alembic.config import Config
from alembic.script import ScriptDirectory
config = Config(str(ROOT / "central" / "alembic.ini"))
config.set_main_option("script_location", str(ROOT / "central" / "alembic"))
script = ScriptDirectory.from_config(config)
migrations = json.loads((ROOT / "release" / "RELEASE_MANIFEST.json").read_text(encoding="utf-8"))["migrations"]
assert migrations["alembic_head_in_repo"] == script.get_current_head()
assert migrations["count"] == len(list(script.walk_revisions()))
def test_production_compose_never_exposes_postgres_or_dev_token():
import yaml
raw = (ROOT / "deploy" / "hub" / "docker-compose.prod.yml").read_text(encoding="utf-8")
doc = yaml.safe_load(raw)
pg, hub = doc["services"]["postgres"], doc["services"]["fiscal-hub"]
assert "ports" not in pg and pg["networks"] == ["internal"] and doc["networks"]["internal"]["internal"] is True
assert any(v.startswith("postgres_data:") for v in pg["volumes"]) and pg["restart"] == "unless-stopped" and "healthcheck" in pg
assert "AGENT_DEV_TOKEN" not in hub["environment"] and hub["environment"]["APP_ENV"] == "production"
assert hub["restart"] == "unless-stopped" and "healthcheck" in hub and hub["depends_on"]["postgres"]["condition"] == "service_healthy"
assert "POSTGRES_PASSWORD:?" in raw and hub["ports"][0].startswith("${HUB_BIND:-127.0.0.1}")
assert set(doc["services"]) == {"postgres", "fiscal-hub"}
images = " ".join(str(v.get("image", "")) for v in doc["services"].values()).lower()
for banned in ("redis", "rabbitmq", "kubernetes"):
assert banned not in images
def test_templates_and_env_examples_contain_no_secrets():
files = list((ROOT / "deploy").rglob("*.example")) + [ROOT / "deploy" / "agent-windows" / "agent.env.template", ROOT / "deploy" / "hub" / ".env.example", ROOT / ".env.example"]
for f in files:
text = f.read_text(encoding="utf-8")
for m in re.finditer(r"^(AGENT_TOKEN|FB_PASSWORD|POSTGRES_PASSWORD|FB_USER)=(.*)$", text, re.M):
assert m.group(2).strip() == "", f"{f.name}: {m.group(1)} must be empty in a template"
pilot = (ROOT / "deploy" / "agent-windows" / "pilot-construcao.env.example").read_text(encoding="utf-8")
assert "COMPANY_CODE=000001" in pilot and "COMPANY_CRT_SOURCE=AUTO" in pilot and "FISCAL_MODE=DRY_RUN" in pilot and "FIREBIRD_WRITES=0" in pilot
for name in ("mmmodas", "rincao", "uniao"):
prof = (ROOT / "deploy" / "agent-windows" / "profiles" / f"{name}.env.example").read_text(encoding="utf-8")
assert "COMPANY_CRT_SOURCE=EMISSOR" in prof and "FISCAL_MODE=DRY_RUN" in prof and "FIREBIRD_WRITES=0" in prof
def test_agent_package_is_self_contained_and_secret_free(tmp_path):
spec = importlib.util.spec_from_file_location("build_agent_package", ROOT / "scripts" / "build_agent_package.py")
mod = importlib.util.module_from_spec(spec); sys.modules[spec.name] = mod; spec.loader.exec_module(mod)
mod.ROOT = ROOT
mod.main()
z = zipfile.ZipFile(ROOT / "dist" / f"{mod.NAME}.zip")
names = z.namelist()
assert len(names) == len(set(names))
for required in ("gti-agent.ps1", "gti-agent.cmd", "requirements-agent.txt", "pilot-construcao.env.example", "agent/scripts/preflight.py", "agent/scripts/run_agent_service.py",
"agent/service/gti_agent_windows_service.py", "scripts/firebird_write_executor.py", "central/app/fiscal_decision.py", "MANIFEST.json", "VERSION"):
assert f"{mod.NAME}/{required}" in names, required
assert not [n for n in names if n.endswith((".env", ".sqlite", ".log", ".FDB"))]
assert f"{mod.NAME}/enrollment.json" not in names # never baked into the universal package — added per-download in the bundle
ps = z.read(f"{mod.NAME}/gti-agent.ps1").decode("utf-8")
for cmd in ("install", "install-auto", "configure", "preflight", "start", "stop", "restart", "status", "uninstall"):
assert f"'{cmd}'" in ps
def test_secret_scan_rejects_a_token_in_a_template():
spec = importlib.util.spec_from_file_location("bap2", ROOT / "scripts" / "build_agent_package.py")
mod = importlib.util.module_from_spec(spec); spec.loader.exec_module(mod)
with pytest.raises(SystemExit):
mod.scan("x.env.example", b"AGENT_TOKEN=abcdefghijklmnop123\n")
mod.scan("x.env.example", b"AGENT_TOKEN=\nAGENT_ID=\n")