feat: release Dever 0.1.5 with direct workers and long transactions

This commit is contained in:
Codex committed 2026-10-11 11:17:33 +00:00
1 parent 89629c2197
commit a900d7e8db
153 files changed
+3676 -3708

No files matched your search

+23 -13
View File
@@ -6,6 +6,7 @@ import hashlib
import importlib.util
import io
import json
import os
from pathlib import Path
import subprocess
import tarfile
@@ -17,6 +18,7 @@ from install_support import load_installer
ROOT = Path(__file__).resolve().parents[2]
ZSTD = Path(os.environ.get("DEVER_TEST_ZSTD", "/usr/bin/zstd"))
def load_module(name, path):
@@ -86,7 +88,7 @@ class InstallerTests(unittest.TestCase):
self.platform, "1.2.3")
def create_assets(self, output):
return assets.create(self.release, output, Path("/usr/bin/zstd"))
return assets.create(self.release, output, ZSTD)
def release_record(self, directory, version="1.2.3"):
return {
@@ -98,7 +100,7 @@ class InstallerTests(unittest.TestCase):
}
def archive_payloads(self, path):
contents = subprocess.run(["/usr/bin/zstd", "-q", "-d", "-c", str(path)],
contents = subprocess.run([str(ZSTD), "-q", "-d", "-c", str(path)],
env={}, capture_output=True, check=True, timeout=15).stdout
with tarfile.open(fileobj=io.BytesIO(contents)) as archive:
return {member.name: archive.extractfile(member).read() for member in archive}
@@ -135,24 +137,32 @@ class InstallerTests(unittest.TestCase):
self.create_assets(first)
def test_extension_assets_are_separate_and_cannot_overlap_base(self):
base_only = self.root / "base-only"
self.create_assets(base_only)
manifest_path = self.release / "manifest.json"
manifest = json.loads(manifest_path.read_text())
name = f"runtime/pip/{self.platform}/runtime.pack"
path = self.release / name
path.parent.mkdir(parents=True)
contents = b"optional Python bytes"
path.write_bytes(contents)
entry = {"path": name, "bytes": len(contents), "sha256": hashlib.sha256(contents).hexdigest()}
manifest["extensions"] = [{"kind": {"type": "runtime", "ecosystem": "pip"},
"target": self.platform, "artifacts": [entry]}]
expected = {}
for ecosystem in ("pip", "npm", "go"):
name = f"runtime/{ecosystem}/{self.platform}/runtime.pack"
path = self.release / name
path.parent.mkdir(parents=True)
contents = f"optional {ecosystem} bytes".encode()
path.write_bytes(contents)
entry = {"path": name, "bytes": len(contents), "sha256": hashlib.sha256(contents).hexdigest()}
manifest["extensions"].append({"kind": {"type": "runtime", "ecosystem": ecosystem},
"target": self.platform, "artifacts": [entry]})
expected[ecosystem] = {name: contents}
manifest_path.write_text(json.dumps(manifest))
self.sign_manifest()
self.authenticate()
output = self.root / "split"
self.create_assets(output)
self.assertEqual(self.archive_payloads(output / f"dever-{self.platform}.tar.zst"), self.payloads)
extension = output / f"dever-{self.platform}.ext-runtime-pip-{self.platform}.tar.zst"
self.assertEqual(self.archive_payloads(extension), {name: contents})
base_name = f"dever-{self.platform}.tar.zst"
self.assertEqual(self.archive_payloads(output / base_name), self.payloads)
self.assertEqual((output / base_name).read_bytes(), (base_only / base_name).read_bytes())
for ecosystem, payloads in expected.items():
extension = output / f"dever-{self.platform}.ext-runtime-{ecosystem}-{self.platform}.tar.zst"
self.assertEqual(self.archive_payloads(extension), payloads)
manifest["extensions"][0]["artifacts"].append(self.catalog["dever-core"])
manifest_path.write_text(json.dumps(manifest))
with self.assertRaisesRegex(ValueError, "resource namespace"):
+7 -4
View File
@@ -78,8 +78,11 @@ def worker_project(image, ecosystem):
def isolated(image, init):
isolator = Path(os.environ["DEVER_TEST_ISOLATOR"])
if not isolator.is_absolute() or not isolator.is_file():
raise ValueError("DEVER_TEST_ISOLATOR requires an absolute test-only executable")
return [
WORKSPACE / "target/sandbox-inputs/assets/bin/bwrap",
isolator,
"--unshare-all", "--die-with-parent", "--new-session", "--bind", image,
"/", "--proc", "/proc", "--dev", "/dev", "--chdir", "/", "--ro-bind",
init, "/fixture-proc-init",
@@ -195,7 +198,7 @@ def ordinary_uid_target_reuse(image):
child.stderr.close()
def install_assets(assets, image, manifest):
def install_assets(assets, image, manifest, trusted_key):
# Only transport is local: signature verification, full tar extraction and
# the final bootstrap executable are the real first-install implementation.
installer = load_installer()
@@ -215,7 +218,7 @@ def install_assets(assets, image, manifest):
installer.download = download
installer.install(argparse.Namespace(
version="latest", release=None, system_root=image, no_start=True,
trusted_key=WORKSPACE / "skills/assets/release.pub",
trusted_key=trusted_key,
))
@@ -238,7 +241,7 @@ def accept(release, assets, image, report, init, extension_helper=None):
try:
minimal_os(image)
if assets:
install_assets(assets, image, manifest)
install_assets(assets, image, manifest, WORKSPACE / "skills/assets/release.pub")
else:
execute([
"/bin/bash", WORKSPACE / "install",
+210 -79
View File
@@ -1,113 +1,244 @@
#!/usr/bin/env python3
"""Actual-asset update transaction in an owned image; never publishes the fixture version."""
"""Actual-version install, upgrade and rollback in an owned container directory."""
import argparse
import hashlib
import json
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
import time
from verify_prepared_release import InstalledDaemon, execute, install_assets, minimal_os, response
from install_support import load_installer
from verify_prepared_release import execute, install_assets, response, worker_project
def prepare_update(image, manifest, key, helper):
# Reuse real payloads under a newly signed, acceptance-only catalog identity.
# This tests the update owner without claiming a second public release exists.
next_manifest = dict(manifest)
major, minor, patch = map(int, manifest["version"].split("."))
version = f"{major}.{minor}.{patch + 1}"
next_manifest["version"] = version
class LocalDaemon:
def __init__(self, machine):
self.machine = machine
self.launcher = machine / "bin/dever"
self.child = None
self.errors = None
def __enter__(self):
self.errors = tempfile.TemporaryFile()
self.child = subprocess.Popen(
[str(self.machine / "bin/deverd"), "--root", str(self.machine)],
env={}, stdout=subprocess.DEVNULL, stderr=self.errors,
)
try:
deadline = time.monotonic() + 10
while time.monotonic() < deadline:
if self.child.poll() is not None:
self.errors.seek(0)
raise RuntimeError(self.errors.read(65536).decode(errors="replace"))
if (self.machine / "state/deverd.sock").is_socket():
self.command("cache", "status")
return self
time.sleep(0.05)
raise RuntimeError("owned compiler daemon did not become ready")
except BaseException:
self.__exit__(None, None, None)
raise
def command(self, *arguments):
return execute([self.launcher, *arguments], timeout=240)
def __exit__(self, *_):
if self.child is not None and self.child.poll() is None:
self.child.terminate()
try:
self.child.wait(timeout=10)
except subprocess.TimeoutExpired:
self.child.kill()
self.child.wait(timeout=10)
if self.errors is not None:
self.errors.close()
def write(root, relative, contents):
path = root / relative
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(contents)
def profile_project(root, profile):
sqlite = {"type": "sqlite", "path": "data/owned.sqlite", "max_connections": 1}
postgres = {"type": "postgres", "url": "postgres://fixture@127.0.0.1:1/unused", "tls": "disabled"}
settings = {
"base": {}, "sqlite": {"database": {"default": sqlite}},
"postgres": {"database": {"default": postgres}},
"both": {"database": {"default": sqlite, "unused": postgres}},
}[profile]
write(root, "config/setting.json", json.dumps(settings))
if profile in ("sqlite", "both"):
write(root, "module/sample/value/model.dever", "type Value { name: Text(1, 32) }\n")
write(root, "module/sample/value/api.dever", "cmd exercise = app.exercise\nlong cmd stages = app.stages\n")
source = '''exercise() (okay: Bool) {
saved = model.create({ name = "pack" })
count = model.count()
removed = model.delete(saved.id)
okay = count == 1 and removed == 1
}
stages() (okay: Bool) {
id = store()
dever.task.sleep(1)
okay = finish(id)
}
transaction store() (id: model.id) {
saved = model.create({ name = "stage" })
id = saved.id
}
transaction finish(id: model.id) (okay: Bool) {
count = model.count()
removed = model.delete(id)
okay = count == 1 and removed == 1
}
'''
else:
write(root, "module/sample/value/api.dever", "cmd exercise = app.exercise\n")
source = "exercise() (okay: Bool) { dever.task.sleep(1)\n okay = true }\n"
write(root, "module/sample/value/app.dever", source)
def fresh_install(args, manifest, passed):
image = args.work / "fresh"
image.mkdir()
install_assets(args.assets, image, manifest, args.trusted_key)
machine = image / "opt/dever"
package = machine / "cache/downloads" / version
package.mkdir()
installed = machine / "versions" / manifest["version"]
for artifact in manifest["artifacts"]:
destination = package / artifact["path"]
destination.parent.mkdir(parents=True, exist_ok=True)
os.link(installed / artifact["path"], destination)
catalog = package / "manifest.json"
catalog.write_text(json.dumps(next_manifest, separators=(",", ":")))
execute([helper, "--sign-catalog", catalog, key])
(machine / "cache/downloads/latest").write_text(version)
return version, hashlib.sha256(catalog.read_bytes()).hexdigest()
programs = []
with LocalDaemon(machine) as daemon:
if daemon.command("version") != manifest["version"]:
raise RuntimeError("fresh installation selected the wrong version")
skill = machine / "versions" / manifest["version"] / "skills/dever-language"
if daemon.command("skill", "path") != str(skill):
raise RuntimeError("installed skill is not paired with the compiler")
if not (skill / "assets/template/module/hello/greeting/app.dever").is_file():
raise RuntimeError("release has no complete project template")
extensions = machine / "cache/extensions"
if extensions.exists() and any(extensions.iterdir()):
raise RuntimeError("fresh base installation installed optional extensions")
project = image / "hello"
daemon.command("new", project)
response(daemon.command("run", project, "--", "hello.greeting.greet", '{"name":"Dever"}'))
passed("fresh_split_base_install_and_full_skill_template")
for profile in ("base", "sqlite", "postgres", "both"):
project = image / f"profile-{profile}"
profile_project(project, profile)
response(daemon.command("run", project, "--", "sample.value.exercise", "{}"), True)
if profile in ("sqlite", "both"):
response(daemon.command("run", project, "--", "sample.value.stages", "{}"), True)
program = project / "program"
daemon.command("build", project, "--output", program)
shutil.rmtree(project / "module")
programs.append((program, "sample.value.exercise", True))
passed("four_runtime_profiles_sqlite_and_long_transactions")
for ecosystem in ("pip", "npm", "go"):
execute([args.extension_helper, machine, args.assets, manifest["version"], f"runtime-{ecosystem}-{manifest['platform']}"])
project = worker_project(image, ecosystem)
daemon.command("lib", "add", project)
response(daemon.command("run", project, "--", "sample.worker.probe", "{}"), True)
program = project / "program"
daemon.command("build", project, "--output", program)
shutil.rmtree(project / "module")
programs.append((program, "sample.worker.probe", True))
passed(f"signed_optional_{ecosystem}_managed_run_and_build")
for program, command, expected in programs:
response(execute([program, command, "{}"]), expected)
passed("source_free_standalone_programs_without_running_daemon")
shutil.rmtree(image)
def upgrade(args, manifest, previous, passed):
image = args.work / "upgrade"
image.mkdir()
original_umask = os.umask(0o022)
try:
load_installer().install(argparse.Namespace(
version=previous["version"], release=args.previous_release,
system_root=image, no_start=True, trusted_key=args.trusted_key,
))
finally:
os.umask(original_umask)
machine = image / "opt/dever"
project = image / "existing-project"
with LocalDaemon(machine) as daemon:
if daemon.command("version") != previous["version"]:
raise RuntimeError("previous installation did not select its actual binary version")
daemon.command("new", project)
response(daemon.command("run", project, "--", "hello.greeting.greet", '{"name":"Dever"}'))
original = (project / "config/setting.json").read_bytes()
passed("actual_previous_release_installed_and_program_runs")
install_assets(args.assets, image, manifest, args.trusted_key)
with LocalDaemon(machine) as daemon:
if daemon.command("version") != manifest["version"]:
raise RuntimeError("upgrade did not select the actual new compiler version")
response(daemon.command("run", project, "--", "hello.greeting.greet", '{"name":"Dever"}'))
if (project / "config/setting.json").read_bytes() != original:
raise RuntimeError("upgrade modified project configuration")
passed("actual_new_release_upgrade_preserves_existing_project")
daemon.command("use", previous["version"])
if daemon.command("version") != previous["version"]:
raise RuntimeError("rollback did not restore the previous compiler")
response(daemon.command("run", project, "--", "hello.greeting.greet", '{"name":"Dever"}'))
passed("rollback_runs_actual_previous_compiler")
daemon.command("use", manifest["version"])
if daemon.command("version") != manifest["version"]:
raise RuntimeError("switch after rollback did not restore the new compiler")
response(daemon.command("run", project, "--", "hello.greeting.greet", '{"name":"Dever"}'))
passed("new_release_runs_again_after_rollback")
shutil.rmtree(image)
def accept(args):
manifest = json.loads((args.release / "manifest.json").read_bytes())
result = {"version": manifest["version"], "checks": [],
"transport": "local actual assets; acceptance-only next-version catalog",
"online_update": "not_run"}
previous = json.loads((args.previous_release / "manifest.json").read_bytes())
if tuple(map(int, manifest["version"].split("."))) <= tuple(map(int, previous["version"].split("."))):
raise ValueError("upgrade requires distinct increasing actual release versions")
args.work.mkdir(mode=0o700)
result = {
"previous_version": previous["version"], "version": manifest["version"],
"checks": [], "errors": {}, "transport": "local signed split assets",
"trust": "explicit acceptance key; not proof of production signing",
"host_language_absence": "not_verified", "gpu": "not_run",
"postgres_server": "not_run", "online_update": "not_run",
"global_service_actions": "not_run",
}
def passed(name):
result["checks"].append(name)
args.report.write_text(json.dumps(result, indent=2) + "\n")
print(f"PASS {name}", flush=True)
try:
args.image.mkdir()
minimal_os(args.image)
install_assets(args.assets, args.image, manifest)
machine = args.image / "opt/dever"
extension = f"runtime-pip-{manifest['platform']}"
execute([args.extension_helper, machine, args.assets, manifest["version"], extension])
records = args.report.parent / f"{args.report.stem}-process"
with InstalledDaemon(args.image, records, args.init) as daemon:
daemon.command("new", "/project")
response(daemon.command("run", "/project", "--", "hello.greeting.greet", '{"name":"Dever"}'))
passed("actual_release_and_selected_extension_before_update")
version, catalog = prepare_update(args.image, manifest, args.key, args.extension_helper)
result["fixture_version"] = version
previous_active = (machine / "state/active-version").read_bytes()
empty_assets = args.image / "missing-extension-assets"
empty_assets.mkdir()
for name, stage in (
("fresh", lambda: fresh_install(args, manifest, passed)),
("upgrade", lambda: upgrade(args, manifest, previous, passed)),
):
try:
execute([args.extension_helper, machine, empty_assets, version, "--update"])
except RuntimeError as error:
if "cannot open actual extension asset" not in str(error):
raise
else:
raise RuntimeError("update with a missing extension should fail")
if (machine / "state/active-version").read_bytes() != previous_active:
raise RuntimeError("failed update changed active version")
if daemon.command("version") != manifest["version"]:
raise RuntimeError("failed update changed the public launcher selection")
response(daemon.command("run", "/project", "--", "hello.greeting.greet", '{"name":"Dever"}'))
passed("failed_extension_update_keeps_old_active_and_application_working")
execute([args.extension_helper, machine, args.assets, version, "--update"])
if daemon.command("version") != version:
raise RuntimeError("successful update did not activate the new version")
if daemon.command("skill", "path") != f"/opt/dever/versions/{version}/skills/dever-language":
raise RuntimeError("skill did not follow the updated core")
extensions = machine / "cache/extensions" / version / catalog
if {path.name for path in extensions.iterdir()} != {extension}:
raise RuntimeError("update did not preserve exactly the installed extension selection")
passed("successful_update_activates_core_skill_and_only_installed_extensions")
# Only the catalog version changes in this transaction fixture.
# The managed compiler correctly requires its real build version;
# execute it again only after selecting the actual release.
daemon.command("use", manifest["version"])
response(daemon.command("run", "/project", "--", "hello.greeting.greet", '{"name":"Dever"}'))
passed("actual_release_remains_usable_after_update_and_explicit_switch_back")
result["status"] = "passed"
except BaseException as error:
result["status"] = "failed"
result["error"] = str(error)
raise
stage()
except (OSError, ValueError, RuntimeError, subprocess.SubprocessError) as error:
result["errors"][name] = str(error)
print(f"FAIL {name}: {error}", flush=True)
result["status"] = "failed" if result["errors"] else "passed"
return not result["errors"]
finally:
args.report.write_text(json.dumps(result, indent=2) + "\n")
def main():
parser = argparse.ArgumentParser(description=__doc__)
for name in ("release", "assets", "image", "report", "init", "extension-helper", "key"):
for name in ("previous-release", "release", "assets", "trusted-key", "work", "report", "extension-helper"):
parser.add_argument(f"--{name}", required=True, type=Path)
args = parser.parse_args()
if os.geteuid() != 0:
parser.error("requires root for an owned image; never installs host services")
parser.error("requires root in an owned validation container; never touches its installed service")
for name, value in vars(args).items():
setattr(args, name, value.absolute())
args.report.parent.mkdir(parents=True, exist_ok=True)
accept(args)
if not value.is_absolute():
parser.error(f"{name} must be an explicit absolute path")
if args.work.exists() or args.work.is_symlink() or args.report.exists():
parser.error("acceptance work/report must be new owned paths")
raise SystemExit(0 if accept(args) else 1)
if __name__ == "__main__":