One universal Windows Agent package per version (agent_releases: version/ platform/architecture/sha256/status DRAFT|PUBLISHED|REVOKED; the binary lives on a local release-storage volume, never in PostgreSQL). An operator creates a pending installation (agent_enrollments) from Agents / Servidores -> + Nova instalação, then either downloads it directly or generates a one-time HTTPS link (short TTL, single use). Either path streams the package plus a freshly minted enrollment.json whose token is never written to storage in plaintext, only its SHA-256 hash. On the client host, gti-agent.ps1 install-auto verifies the bundle's SHA-256, refuses a non- HTTPS Hub, enrolls via POST /v1/agents/enroll (deleting the enrollment token immediately after, success or failure), writes an ACL-restricted .env with the newly issued permanent Agent token, and registers the Windows Service without starting it (Firebird stays unconfigured on purpose). Idempotent, replay-proof, rate-limited per IP, fully audited, never logs a secret. Migration 0022_agent_releases_enrollment (verified fresh-DB == upgrade-from-0021 by pg_dump diff). GTI_FISCAL_VERSION/AGENT_VERSION bumped to 1.1.0 as the single source of truth across code, packages, the release manifest and every published AgentRelease row. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
64 lines
2.5 KiB
Python
64 lines
2.5 KiB
Python
"""Static checks on deploy/agent-windows/gti-agent.ps1's `install-auto` command
|
|
(the zero-touch path driven by the enrollment bundle from the panel). No
|
|
Windows host is available in CI, so these are text-level guarantees — the
|
|
same properties are exercised for real in the manual Windows smoke test
|
|
described in docs/PILOT_DEPLOYMENT.md.
|
|
"""
|
|
import re
|
|
from pathlib import Path
|
|
|
|
SCRIPT = (Path(__file__).parents[2] / "deploy" / "agent-windows" / "gti-agent.ps1").read_text(encoding="utf-8")
|
|
|
|
|
|
def install_auto_block() -> str:
|
|
start = SCRIPT.index("'install-auto' {")
|
|
end = SCRIPT.index("'configure' {")
|
|
return SCRIPT[start:end]
|
|
|
|
|
|
def test_install_auto_is_a_registered_command():
|
|
validate_set = re.search(r"ValidateSet\(([^)]*)\)", SCRIPT).group(1)
|
|
assert "'install-auto'" in validate_set
|
|
|
|
|
|
def test_install_auto_never_enables_firebird_writes():
|
|
block = install_auto_block()
|
|
assert "FIREBIRD_WRITES=0" in block
|
|
assert "FIREBIRD_WRITES=1" not in SCRIPT # nowhere in the whole script, not just this block
|
|
|
|
|
|
def test_install_auto_refuses_a_non_https_hub():
|
|
assert "hub_url -notmatch '^https://'" in install_auto_block()
|
|
|
|
|
|
def test_install_auto_verifies_package_sha256_before_installing():
|
|
block = install_auto_block()
|
|
assert "SHA256_VALIDATION" in block and "Get-FileHash" in block
|
|
assert block.index("SHA256_VALIDATION") < block.index("Invoke-RestMethod") # integrity checked before any network call
|
|
|
|
|
|
def test_install_auto_deletes_the_enrollment_bundle_after_use():
|
|
block = install_auto_block()
|
|
assert "Remove-Item $EnrollmentFile -Force" in block
|
|
assert block.index("Remove-Item $EnrollmentFile") > block.index("Invoke-RestMethod") # only after a successful enroll
|
|
|
|
|
|
def test_install_auto_registers_but_never_starts_the_service():
|
|
block = install_auto_block()
|
|
assert "install" in block and "Start-Service" not in block # Firebird config is still missing; starting it is a separate, explicit step
|
|
|
|
|
|
def test_install_auto_never_hardcodes_a_client_firebird_path():
|
|
block = install_auto_block()
|
|
assert "'FIREBIRD_DATABASE_PATH='" in block # written, but as an empty placeholder (no real path baked in)
|
|
|
|
|
|
def test_install_auto_restricts_the_env_file_acl():
|
|
block = install_auto_block()
|
|
assert "icacls $EnvFile /inheritance:r /grant:r 'Administrators:(F)' 'SYSTEM:(F)'" in block
|
|
|
|
|
|
def test_install_auto_is_idempotent_when_already_enrolled():
|
|
block = install_auto_block()
|
|
assert "Already enrolled and installed" in block and "exit 0" in block
|