Add automatic agent updates with verified rollback

This commit is contained in:
2026-10-04 10:40:45 -04:00
parent 020894b816
commit 8d1331c67d
26 changed files with 2568 additions and 110 deletions
+30 -6
View File
@@ -1,13 +1,37 @@
#!/usr/bin/env python3
"""Publish the reviewed local agent source into the controller static release."""
import ast
import hashlib
import json
from pathlib import Path
import re
import shutil
source = Path(__file__).resolve().parent
target = source.parent / "static" / "agent"
target.mkdir(parents=True, exist_ok=True)
shutil.copyfile(source / "ec_agent.py", target / "ec-agent.py")
shutil.copyfile(source / "install.sh", target / "install.sh")
(target / "manifest.json").write_text(json.dumps({"version": "1.1.0", "protocolVersion": 1, "platform": "debian-amd64", "sha256": hashlib.sha256((target / "ec-agent.py").read_bytes()).hexdigest()}, indent=2) + "\n")
def package(source, target):
"""Read version metadata without importing or executing release code."""
source, target = Path(source), Path(target)
agent = (source / "ec_agent.py").read_bytes()
updater = (source / "ec_agent_update.py").read_bytes()
versions = [node.value.value for node in ast.parse(agent).body
if isinstance(node, ast.Assign) and any(isinstance(name, ast.Name) and name.id == "VERSION" for name in node.targets)
and isinstance(node.value, ast.Constant) and isinstance(node.value.value, str)]
if len(versions) != 1 or not re.fullmatch(r"(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)", versions[0]):
raise ValueError("Agent source must declare exactly one literal semantic VERSION")
compile(agent, "ec_agent.py", "exec")
compile(updater, "ec_agent_update.py", "exec")
manifest = {"version": versions[0], "protocolVersion": 1, "platform": "debian-amd64",
"sha256": hashlib.sha256(agent).hexdigest(), "updaterProtocolVersion": 1,
"updaterSha256": hashlib.sha256(updater).hexdigest()}
target.mkdir(parents=True, exist_ok=True)
(target / "ec-agent.py").write_bytes(agent)
(target / "ec-agent-update.py").write_bytes(updater)
shutil.copyfile(source / "install.sh", target / "install.sh")
temporary_manifest = target / ".manifest.json.tmp"
temporary_manifest.write_text(json.dumps(manifest, indent=2) + "\n")
temporary_manifest.replace(target / "manifest.json")
if __name__ == "__main__":
source = Path(__file__).resolve().parent
package(source, source.parent / "static" / "agent")