Files
core/test/onboarding/verify_install_entry.py
T

134 lines
6.1 KiB
Python

#!/usr/bin/python3
"""Opt-in root install acceptance in an owned image, without host services."""
import argparse
import hashlib
import json
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
from verify_prepared_release import WORKSPACE, execute
def verify(args):
result = {
"status": "running", "checks": [],
"transport": "local signed assets; actual root Bash entry and Rust bootstrap",
"online_install_and_update": "not_run",
"entry_sha256": hashlib.sha256(args.entry.read_bytes()).hexdigest(),
}
def passed(name):
result["checks"].append(name)
args.report.write_text(json.dumps(result, indent=2) + "\n")
print(f"PASS {name}", flush=True)
try:
with tempfile.TemporaryDirectory(prefix="dever-install-entry-", dir=args.scratch_parent) as directory:
scratch = Path(directory)
release = scratch / "release"
release.mkdir()
for name in ("manifest.json", "manifest.sig"):
shutil.copyfile(args.release / name, release / name)
manifest = json.loads((release / "manifest.json").read_bytes())
if manifest["platform"] != "linux-x86_64":
raise ValueError("this acceptance fixture requires a Linux x86_64 release")
result["payload_version"] = manifest["version"]
result["manifest_sha256"] = hashlib.sha256((release / "manifest.json").read_bytes()).hexdigest()
key = scratch / "release.pub"
shutil.copyfile(WORKSPACE / "skills/assets/release.pub", key)
extraction = scratch / "extract.json"
extraction.write_text(json.dumps({
"release": str(release),
"archive": str(args.assets / "dever-linux-x86_64.tar.zst"),
"trusted_key": str(key),
}))
execute([args.extractor, "--dever-extract", extraction])
passed("prepared_release_authenticated_by_existing_rust_extractor")
# A copied standalone entry has no adjacent skill or source checkout.
entry = scratch / "install"
shutil.copyfile(args.entry, entry)
image = scratch / "image"
image.mkdir()
arguments = ["--release", str(release), "--system-root", str(image), "--no-start"]
execute(["/bin/bash", entry, *arguments])
machine = image / "opt/dever"
launcher = machine / "bin/dever"
installed = machine / "versions" / manifest["version"]
if execute([launcher, "version"]) != manifest["version"]:
raise RuntimeError("installed launcher selected the wrong version")
skill = installed / "skills/dever-language"
if execute([launcher, "skill", "path"]) != str(skill):
raise RuntimeError("installed skill does not match the selected core")
if (image / "usr/local/bin/dever").readlink() != Path("/opt/dever/bin/dever"):
raise RuntimeError("public launcher symlink was not installed")
passed("standalone_bash_first_install_and_matching_skill")
tracked = [launcher, machine / "bin/deverd",
installed / "manifest.json", installed / "dever-core"]
baseline = {str(path): hashlib.sha256(path.read_bytes()).hexdigest() for path in tracked}
def unchanged():
current = {str(path): hashlib.sha256(path.read_bytes()).hexdigest() for path in tracked}
if current != baseline:
raise RuntimeError("existing installed state changed")
if list(image.glob(".dever-install-*")):
raise RuntimeError("installer left private staging behind")
repeated = subprocess.run(
["/bin/bash", "-s", "--", *arguments], input=entry.read_bytes(),
cwd=scratch, env={}, capture_output=True, timeout=180,
)
if repeated.returncode:
raise RuntimeError(repeated.stderr.decode(errors="replace"))
unchanged()
# Bootstrap records another activation even for the same version.
# Compare the selected version here, then freeze the journal for failure checks.
if execute([launcher, "version"]) != manifest["version"]:
raise RuntimeError("reinstall changed the selected version")
active = machine / "state/active-version"
tracked.append(active)
baseline[str(active)] = hashlib.sha256(active.read_bytes()).hexdigest()
passed("pipe_reinstall_preserves_installed_state_and_cleans_staging")
(release / "manifest.sig").write_text("00" * 64 + "\n")
rejected = subprocess.run(
["/bin/bash", entry, *arguments], cwd=scratch, env={},
capture_output=True, timeout=30,
)
if rejected.returncode == 0 or "签名校验失败" not in rejected.stderr.decode(errors="replace"):
raise RuntimeError("corrupt signature did not fail at authentication")
unchanged()
if execute([launcher, "version"]) != manifest["version"]:
raise RuntimeError("failed install changed the selected version")
passed("corrupt_signature_rejected_existing_install_preserved")
result["status"] = "passed"
except BaseException as error:
result["status"] = "failed"
result["error"] = str(error)
raise
finally:
args.report.write_text(json.dumps(result, indent=2) + "\n")
def main():
parser = argparse.ArgumentParser(description=__doc__)
for name in ("release", "assets", "extractor", "scratch-parent", "report"):
parser.add_argument(f"--{name}", required=True, type=Path)
parser.add_argument("--entry", type=Path, default=WORKSPACE / "install")
args = parser.parse_args()
if os.geteuid() != 0:
parser.error("requires root for its own image; never installs host services")
for name, value in vars(args).items():
setattr(args, name, value.absolute())
args.report.parent.mkdir(parents=True, exist_ok=True)
verify(args)
if __name__ == "__main__":
main()