chore: establish project baseline
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
"""Build the GTI Fiscal Agent Windows package (zip) and verify it contains no secrets.
|
||||
|
||||
python scripts/build_agent_package.py -> dist/GTIFiscalAgent-<version>.zip (+ .sha256)
|
||||
|
||||
The zip root is the install folder:
|
||||
gti-agent.ps1 / gti-agent.cmd / requirements-agent.txt / agent.env.template / pilot-construcao.env.example / profiles/
|
||||
agent/{src,scripts,service}, scripts/firebird_write_executor.py, central/app/{engine modules}, VERSION, MANIFEST.json
|
||||
"""
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
VERSION = (ROOT / "release" / "VERSION").read_text(encoding="utf-8").strip()
|
||||
NAME = f"GTIFiscalAgent-{VERSION}"
|
||||
|
||||
INCLUDE = [ # (source, destination inside the package)
|
||||
*[(p, str(p.relative_to(ROOT)).replace("\\", "/")) for p in sorted((ROOT / "agent" / "src" / "gti_fiscal_agent").glob("*.py"))],
|
||||
(ROOT / "agent" / "scripts" / "run_agent_service.py", "agent/scripts/run_agent_service.py"),
|
||||
(ROOT / "agent" / "scripts" / "preflight.py", "agent/scripts/preflight.py"),
|
||||
(ROOT / "agent" / "service" / "gti_agent_windows_service.py", "agent/service/gti_agent_windows_service.py"),
|
||||
(ROOT / "scripts" / "firebird_write_executor.py", "scripts/firebird_write_executor.py"),
|
||||
(ROOT / "central" / "__init__.py", "central/__init__.py"),
|
||||
*[(ROOT / "central" / "app" / f, f"central/app/{f}") for f in ("__init__.py", "fiscal_decision.py", "dry_run_planner.py", "product_defaults.py", "icms_context.py")],
|
||||
*[(p, p.name) for p in sorted((ROOT / "deploy" / "agent-windows").glob("*")) if p.is_file()],
|
||||
*[(p, f"profiles/{p.name}") for p in sorted((ROOT / "deploy" / "agent-windows" / "profiles").glob("*")) if p.is_file()],
|
||||
(ROOT / "release" / "VERSION", "VERSION"),
|
||||
]
|
||||
SECRET_PATTERNS = [
|
||||
(re.compile(r"^[ ]*(AGENT_TOKEN|FB_PASSWORD|POSTGRES_PASSWORD)[ ]*=[ ]*\S+", re.M), "non-empty secret assignment"),
|
||||
(re.compile(r"masterkey", re.I), "default Firebird password"),
|
||||
(re.compile(r"[A-Za-z0-9_\-]{40,}"), "long token-like string"),
|
||||
]
|
||||
ALLOWED_LONG = re.compile(r"^[A-Za-z0-9_\-]{40,}$")
|
||||
|
||||
|
||||
def scan(name, data):
|
||||
if name.endswith((".ps1", ".cmd", ".py", ".txt", ".example", ".template", "VERSION")):
|
||||
text = data.decode("utf-8", "replace")
|
||||
for rx, why in SECRET_PATTERNS:
|
||||
for m in rx.finditer(text):
|
||||
token = m.group(0)
|
||||
if why == "long token-like string" and (token.startswith(("_", "-")) or "_" in token and token.count("_") > 3 or token.isalpha()):
|
||||
continue # identifiers / prose, not a secret
|
||||
if why == "long token-like string" and not re.search(r"\d", token):
|
||||
continue
|
||||
if why == "long token-like string" and re.fullmatch(r"[0-9a-f]{64}", token):
|
||||
continue # schema fingerprint (public SHA-256), not a secret
|
||||
raise SystemExit(f"secret scan failed in {name}: {why}: {token[:6]}...")
|
||||
|
||||
|
||||
def main():
|
||||
dist = ROOT / "dist"
|
||||
dist.mkdir(exist_ok=True)
|
||||
out = dist / f"{NAME}.zip"
|
||||
manifest = {"name": NAME, "version": VERSION, "files": {}}
|
||||
with zipfile.ZipFile(out, "w", zipfile.ZIP_DEFLATED) as z:
|
||||
for src, dst in INCLUDE:
|
||||
data = Path(src).read_bytes()
|
||||
assert not dst.endswith((".env", ".sqlite", ".log", ".FDB")), dst
|
||||
scan(dst, data)
|
||||
manifest["files"][dst] = hashlib.sha256(data).hexdigest()
|
||||
z.writestr(f"{NAME}/{dst}", data)
|
||||
z.writestr(f"{NAME}/MANIFEST.json", json.dumps(manifest, indent=1))
|
||||
digest = hashlib.sha256(out.read_bytes()).hexdigest()
|
||||
(dist / f"{NAME}.zip.sha256").write_text(f"{digest} {out.name}\n", encoding="utf-8")
|
||||
print(json.dumps({"package": str(out.relative_to(ROOT)), "files": len(manifest["files"]), "sha256": digest}))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user