feat: unify source and skills for Dever 0.1.2 installation
This commit is contained in:
1 parent
a2e0436ed4
commit
19f122b4b4
47 files changed
+1951
-63
No files matched your search
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/python3
|
||||
"""Opt-in real Bash installer 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 generated 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()
|
||||
Reference in new issue
Block a user