feat: release Dever 0.1.5 with direct workers and long transactions
This commit is contained in:
1 parent
89629c2197
commit
a900d7e8db
153 files changed
+3676
-3708
No files matched your search
@@ -17,8 +17,8 @@ mod daemon;
|
||||
mod inputs;
|
||||
#[path = "../../dever-tests/tests/support/process.rs"]
|
||||
mod process;
|
||||
#[path = "../../dever-tests/tests/support/sandbox.rs"]
|
||||
mod sandbox;
|
||||
#[path = "../../dever-tests/tests/support/process_runtime.rs"]
|
||||
mod process_runtime;
|
||||
use super::temp::TemporaryDirectory;
|
||||
|
||||
#[path = "ecosystem_acceptance.rs"]
|
||||
@@ -147,11 +147,15 @@ fn author_inputs(author: &Path, workspace: &Path) -> Ed25519KeyPair {
|
||||
),
|
||||
);
|
||||
}
|
||||
let compiler = input(author, Path::new(env!("CARGO_BIN_EXE_dever")), "dever");
|
||||
let compiler = input(
|
||||
author,
|
||||
&workspace.join("target/native-release-inputs/bin/dever"),
|
||||
"dever",
|
||||
);
|
||||
let core_libraries = inputs::core_libraries()
|
||||
.into_iter()
|
||||
.map(|(name, source)| {
|
||||
let mut value = input(author, &source, name);
|
||||
let mut value = input(author, &source, &name);
|
||||
value["path"] = json!(name);
|
||||
value
|
||||
})
|
||||
@@ -171,11 +175,11 @@ fn author_inputs(author: &Path, workspace: &Path) -> Ed25519KeyPair {
|
||||
.map(|name| links[*name].clone())
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
let sandbox = sandbox::assets(workspace).into_iter().map(|asset| {
|
||||
let process_runtime = process_runtime::assets(workspace).into_iter().map(|asset| {
|
||||
let relative = format!("inputs/{}", asset.path);
|
||||
write(author, &relative, &asset.bytes);
|
||||
fs::set_permissions(author.join(&relative), fs::Permissions::from_mode(if asset.executable { 0o755 } else { 0o644 })).unwrap();
|
||||
json!({"source":relative, "path":asset.path.strip_prefix("sandbox/").unwrap(), "sha256":sha256_file(&author.join(&relative)).unwrap()})
|
||||
json!({"source":relative, "path":asset.path.strip_prefix("process-runtime/").unwrap(), "sha256":sha256_file(&author.join(&relative)).unwrap()})
|
||||
}).collect::<Vec<_>>();
|
||||
write(
|
||||
author,
|
||||
@@ -193,7 +197,7 @@ fn author_inputs(author: &Path, workspace: &Path) -> Ed25519KeyPair {
|
||||
"skill":[skill],
|
||||
"start":ordered(&["crt1.o","crti.o","crtbeginT.o"]),
|
||||
"libraries":ordered(&["libc.a","libm.a","libmvec.a","libgcc.a","libgcc_eh.a"]),
|
||||
"end":ordered(&["crtend.o","crtn.o"]), "sandbox":sandbox
|
||||
"end":ordered(&["crtend.o","crtn.o"]), "process_runtime":process_runtime
|
||||
}))
|
||||
.unwrap(),
|
||||
);
|
||||
@@ -211,10 +215,11 @@ fn isolated_os_command(root: &Path) -> Command {
|
||||
}
|
||||
|
||||
fn isolated_os_namespace(root: &Path) -> Command {
|
||||
let assets = Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("../../target/sandbox-inputs/assets")
|
||||
.canonicalize()
|
||||
.expect("prepare the explicit Linux isolation assets");
|
||||
let isolator = PathBuf::from(
|
||||
std::env::var_os("DEVER_TEST_ISOLATOR")
|
||||
.expect("set an absolute test-only namespace isolator path"),
|
||||
);
|
||||
assert!(isolator.is_absolute());
|
||||
let init = Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("../../target/debug/examples/native-acceptance-init")
|
||||
.canonicalize()
|
||||
@@ -222,10 +227,7 @@ fn isolated_os_namespace(root: &Path) -> Command {
|
||||
let bytes = fs::read(&init).unwrap();
|
||||
let executable = goblin::elf::Elf::parse(&bytes).unwrap();
|
||||
assert!(executable.interpreter.is_none() && executable.libraries.is_empty());
|
||||
// A plain chroot cannot create a nested user namespace. Use a real mount
|
||||
// namespace root so the program can retain its normal Worker sandbox.
|
||||
dever_sandbox::validate_bwrap(&fs::read(assets.join("bin/bwrap")).unwrap()).unwrap();
|
||||
let mut command = Command::new(assets.join("bin/bwrap"));
|
||||
let mut command = Command::new(isolator);
|
||||
command
|
||||
.env_clear()
|
||||
.args([
|
||||
@@ -301,6 +303,33 @@ fn application(root: &Path, profile: &str) {
|
||||
"exercise() (okay: Bool) { dever.task.sleep(1)\n okay = true }\n"
|
||||
};
|
||||
write(root, "module/sample/value/app.dever", app);
|
||||
if matches!(profile, "sqlite" | "both") {
|
||||
write(
|
||||
root,
|
||||
"module/sample/value/api.dever",
|
||||
"cmd exercise = app.exercise\nlong cmd stages = app.stages\n",
|
||||
);
|
||||
write(
|
||||
root,
|
||||
"module/sample/value/app.dever",
|
||||
format!(
|
||||
"{app}\nstages() (okay: Bool) {{ id = store()\n dever.task.sleep(1)\n okay = finish(id) }}\ntransaction store() (id: model.id) {{ saved = model.create({{ name = \"stage\" }})\n id = saved.id }}\ntransaction finish(id: model.id) (okay: Bool) {{ count = model.count()\n removed = model.delete(id)\n okay = count == 1 and removed == 1 }}\n"
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn release_profile_projects_have_valid_source_contracts() {
|
||||
for profile in PROFILES {
|
||||
let project = TemporaryDirectory::new();
|
||||
application(project.path(), profile);
|
||||
command(
|
||||
Command::new(env!("CARGO_BIN_EXE_dever"))
|
||||
.arg("check")
|
||||
.arg(project.path()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_response(output: Output) {
|
||||
@@ -489,7 +518,7 @@ fn signed_core_builds_without_host_compiler_libraries_or_tools() {
|
||||
#[test]
|
||||
#[ignore = "requires four optimized archives and component-fixture; starts only an owned daemon, SQLite and exec Worker fixtures"]
|
||||
fn optimized_profiles_make_reproducible_signed_release_and_run_through_daemon() {
|
||||
let workspace = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
|
||||
let workspace = inputs::workspace();
|
||||
let profiles = archive_report(&workspace);
|
||||
let author = TemporaryDirectory::new();
|
||||
let key = author_inputs(author.path(), &workspace);
|
||||
@@ -505,7 +534,7 @@ fn optimized_profiles_make_reproducible_signed_release_and_run_through_daemon()
|
||||
let version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
||||
let release = layout.downloads().join(version.as_str());
|
||||
command(
|
||||
Command::new(workspace.join("target/debug/examples/native-release"))
|
||||
Command::new(workspace.join("target/native-release-inputs/bin/native-release"))
|
||||
.arg(author.path())
|
||||
.arg("--output")
|
||||
.arg(&release),
|
||||
@@ -523,10 +552,13 @@ fn optimized_profiles_make_reproducible_signed_release_and_run_through_daemon()
|
||||
fs::remove_dir_all(&release).unwrap();
|
||||
drop(author);
|
||||
let compiler = layout.versions().join(version.as_str()).join("dever-core");
|
||||
let mut daemon = daemon::TestDaemon::start(&layout);
|
||||
let mut daemon = daemon::TestDaemon::start_with_executable(
|
||||
&layout,
|
||||
&workspace.join("target/native-release-inputs/bin/deverd"),
|
||||
);
|
||||
let projects = TemporaryDirectory::new();
|
||||
let mut binaries = serde_json::Map::new();
|
||||
let mut programs: Vec<(PathBuf, PathBuf)> = Vec::new();
|
||||
let mut programs = Vec::new();
|
||||
for profile in PROFILES {
|
||||
let project = projects.path().join(profile);
|
||||
application(&project, profile);
|
||||
@@ -538,6 +570,15 @@ fn optimized_profiles_make_reproducible_signed_release_and_run_through_daemon()
|
||||
"{}",
|
||||
]),
|
||||
));
|
||||
if matches!(profile, "sqlite" | "both") {
|
||||
assert_response(command(
|
||||
Command::new(&compiler).arg("run").arg(&project).args([
|
||||
"--",
|
||||
"sample.value.stages",
|
||||
"{}",
|
||||
]),
|
||||
));
|
||||
}
|
||||
let executable = project.join("program");
|
||||
command(
|
||||
Command::new(&compiler)
|
||||
@@ -547,7 +588,7 @@ fn optimized_profiles_make_reproducible_signed_release_and_run_through_daemon()
|
||||
.arg(&executable),
|
||||
);
|
||||
binaries.insert(profile.into(), json!({"bytes":fs::metadata(&executable).unwrap().len(),"sha256":sha256_file(&executable).unwrap()}));
|
||||
programs.push((project, executable));
|
||||
programs.push((profile, project, executable));
|
||||
}
|
||||
assert_eq!(cache_status(&layout).unwrap().entries, 4);
|
||||
let exec_project = TemporaryDirectory::new();
|
||||
@@ -595,19 +636,25 @@ fn optimized_profiles_make_reproducible_signed_release_and_run_through_daemon()
|
||||
"managed_run": true, "standalone_run": true,
|
||||
"source_project_removed": true, "response": 7
|
||||
});
|
||||
for (project, executable) in programs {
|
||||
for (profile, project, executable) in programs {
|
||||
fs::remove_dir_all(project.join("module")).unwrap();
|
||||
assert_response(command(
|
||||
Command::new(executable).args(["sample.value.exercise", "{}"]),
|
||||
Command::new(&executable).args(["sample.value.exercise", "{}"]),
|
||||
));
|
||||
if matches!(profile, "sqlite" | "both") {
|
||||
assert_response(command(
|
||||
Command::new(executable).args(["sample.value.stages", "{}"]),
|
||||
));
|
||||
}
|
||||
}
|
||||
let report = json!({
|
||||
"format":"dever-native-release-acceptance-v1", "platform":"linux-x86_64",
|
||||
"version":version.as_str(), "profiles":profiles,"programs":binaries,"exec":exec,
|
||||
"manifest_sha256":format!("{:x}", sha2::Sha256::digest(&manifest)),
|
||||
"checks":{"pack_determinism":true,"signed_install":true,"managed_profiles":4,"standalone_profiles":4,"sqlite_crud":true,"signed_exec_worker":true},
|
||||
"checks":{"pack_determinism":true,"signed_install":true,"managed_profiles":4,"standalone_profiles":4,"sqlite_crud":true,"long_staged_transactions":true,"signed_exec_worker":true},
|
||||
"postgres_server":"not_run", "cross_host_source_reproducibility":"not_run"
|
||||
});
|
||||
retain_candidate(&layout, &version, "native", &report);
|
||||
use sha2::Digest;
|
||||
write(
|
||||
&workspace,
|
||||
@@ -615,3 +662,45 @@ fn optimized_profiles_make_reproducible_signed_release_and_run_through_daemon()
|
||||
serde_json::to_vec_pretty(&report).unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
fn retain_candidate(layout: &Layout, version: &Version, name: &str, report: &Value) {
|
||||
let Some(destination) = std::env::var_os("DEVER_NATIVE_ACCEPTANCE_OUTPUT") else {
|
||||
return;
|
||||
};
|
||||
let destination = PathBuf::from(destination);
|
||||
assert!(destination.is_absolute());
|
||||
fs::create_dir_all(&destination).unwrap();
|
||||
let destination = destination.join(name);
|
||||
fs::create_dir(&destination).unwrap();
|
||||
let payload = destination.join("release");
|
||||
let resources = dever_cli::toolchain::SignedResources::load(layout, version).unwrap();
|
||||
let manifest = resources.manifest();
|
||||
for artifact in manifest.artifacts.iter().chain(
|
||||
manifest
|
||||
.extensions
|
||||
.iter()
|
||||
.flat_map(|extension| &extension.artifacts),
|
||||
) {
|
||||
let output = payload.join(&artifact.path);
|
||||
fs::create_dir_all(output.parent().unwrap()).unwrap();
|
||||
fs::copy(resources.path(&artifact.path).unwrap(), &output).unwrap();
|
||||
assert_eq!(sha256_file(&output).unwrap(), artifact.sha256);
|
||||
}
|
||||
for file in ["manifest.json", "manifest.sig"] {
|
||||
fs::copy(
|
||||
layout.versions().join(version.as_str()).join(file),
|
||||
payload.join(file),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
fs::copy(
|
||||
layout.state().join("trusted-release-key"),
|
||||
destination.join("test-release.pub"),
|
||||
)
|
||||
.unwrap();
|
||||
fs::write(
|
||||
destination.join("verification.json"),
|
||||
serde_json::to_vec_pretty(report).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
Reference in new issue
Block a user