Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,220 @@
|
||||
//! 真实签名测试包通过 production prepare 编译与执行,并验证源码移除后的行为。
|
||||
|
||||
use super::*;
|
||||
use crate::compiler::{build, project::Project};
|
||||
use std::{fs, path::Path, process::Command};
|
||||
#[path = "build_fixture.rs"]
|
||||
mod fixture;
|
||||
|
||||
struct EmptyStore;
|
||||
impl Store for EmptyStore {
|
||||
fn get(&self, _: &str, _: u64) -> Result<Option<Vec<u8>>, String> {
|
||||
Ok(None)
|
||||
}
|
||||
fn put(&self, _: &[u8]) -> Result<(), String> {
|
||||
panic!("Worker prepare must not write cache")
|
||||
}
|
||||
}
|
||||
|
||||
fn project(root: &Path) {
|
||||
for (path, source) in [
|
||||
("app", "value() (value: Int) { value = port.native() }\n"),
|
||||
("port", "native() (value: Int) fails dever.api.Error\n"),
|
||||
("adapter", "external go \"worker/main.go\" {}\n"),
|
||||
("api", "cmd value = app.value\n"),
|
||||
] {
|
||||
fixture::write(root, &format!("module/demo/value/{path}.dever"), source);
|
||||
}
|
||||
fixture::write(
|
||||
root,
|
||||
"module/demo/value/worker/main.go",
|
||||
"package main\nimport (\"context\"; _ \"embed\"; \"dever-worker/helper\")\n//go:embed note.txt\nvar note string\nfunc Native(_ context.Context, _ any, _ any) (any, error) { return map[string]any{\"value\":helper.Value()+Target()+int64(len(note))}, nil }\n",
|
||||
);
|
||||
fixture::write(
|
||||
root,
|
||||
"module/demo/value/worker/helper/value.go",
|
||||
"package helper\nimport \"dever-worker/helper/internal/value\"\nfunc Value() int64 { return value.Get() }\n",
|
||||
);
|
||||
fixture::write(
|
||||
root,
|
||||
"module/demo/value/worker/helper/internal/value/value.go",
|
||||
"package value\nfunc Get() int64 { return 40 }\n",
|
||||
);
|
||||
fixture::write(
|
||||
root,
|
||||
"module/demo/value/worker/target_linux.go",
|
||||
"//go:build linux\npackage main\nfunc Target() int64 { return 1 }\n",
|
||||
);
|
||||
fixture::write(
|
||||
root,
|
||||
"module/demo/value/worker/target_windows.go",
|
||||
"//go:build windows\npackage main\nfunc Target() int64 { return 99 }\n",
|
||||
);
|
||||
fixture::write(root, "module/demo/value/worker/note.txt", "x");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "explicit dev-Pod Go authoring fixture; no product tool fallback"]
|
||||
fn signed_go_pack_compiles_reproducibly_and_runs_native_after_source_removal() {
|
||||
let fixture = fixture::Fixture::new();
|
||||
let root = fixture.root.join("project");
|
||||
project(&root);
|
||||
let project = Project::load(&root).unwrap();
|
||||
let program = project.check().unwrap();
|
||||
let external = program.external_workers().next().unwrap();
|
||||
let target = BuildTarget::host().unwrap();
|
||||
let metadata = library::runtime::metadata(&fixture.signed, "go", target).unwrap();
|
||||
let mut worker = Worker::from_external(external).unwrap();
|
||||
worker.runtime = Some(metadata.pack.clone());
|
||||
let mut lock = Lock::new(vec![]);
|
||||
lock.workers.push(worker);
|
||||
fixture::write(&root, "dever.lock", lock.encode().unwrap());
|
||||
let prepare = || {
|
||||
crate::compiler::project::dependency::worker::prepare_with_store(
|
||||
&root,
|
||||
&program,
|
||||
target,
|
||||
&fixture.signed,
|
||||
&EmptyStore,
|
||||
)
|
||||
};
|
||||
let files = prepare().unwrap();
|
||||
let repeated = prepare().unwrap();
|
||||
assert_eq!(
|
||||
files
|
||||
.iter()
|
||||
.map(|file| (&file.path, &file.bytes, file.executable))
|
||||
.collect::<Vec<_>>(),
|
||||
repeated
|
||||
.iter()
|
||||
.map(|file| (&file.path, &file.bytes, file.executable))
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
assert!(!files.iter().any(|file| file.path.contains("/source/")
|
||||
|| file.path.contains("/stdlib/")
|
||||
|| file.path.ends_with("component.go")));
|
||||
let binary = build::build_with_resources(
|
||||
&program,
|
||||
&project.sources,
|
||||
"main",
|
||||
&root.join("app"),
|
||||
target,
|
||||
&files,
|
||||
)
|
||||
.unwrap();
|
||||
// 工具与 SDK 篡改、闭包缺失和目标被排除都必须在交付 Worker 前失败。
|
||||
let installation = fixture.root.join("installation");
|
||||
let release = installation.join("versions/0.0.1");
|
||||
let signature = release.join("manifest.sig");
|
||||
let original = fs::read(&signature).unwrap();
|
||||
fs::write(&signature, "00".repeat(64)).unwrap();
|
||||
assert!(SignedResources::load(&installation, "0.0.1").is_err());
|
||||
fs::write(&signature, original).unwrap();
|
||||
for relative in [
|
||||
"sdk/go/component.go".into(),
|
||||
format!("runtime/go/{}/runtime.pack", target.name()),
|
||||
format!("runtime/go/{}/manifest.json", target.name()),
|
||||
] {
|
||||
let path = release.join(relative);
|
||||
let original = fs::read(&path).unwrap();
|
||||
let mut changed = original.clone();
|
||||
let middle = changed.len() / 2;
|
||||
changed[middle] ^= 1;
|
||||
fs::write(&path, changed).unwrap();
|
||||
assert!(
|
||||
prepare()
|
||||
.err()
|
||||
.expect("tampered signed asset was accepted")
|
||||
.contains("signed resource bytes differ")
|
||||
);
|
||||
fs::write(&path, original).unwrap();
|
||||
let saved = fixture.root.join("missing-asset");
|
||||
fs::rename(&path, &saved).unwrap();
|
||||
assert!(prepare().is_err(), "missing asset used a host fallback");
|
||||
fs::rename(saved, path).unwrap();
|
||||
}
|
||||
let main = root.join("module/demo/value/worker/main.go");
|
||||
let source = fs::read_to_string(&main).unwrap();
|
||||
fs::write(
|
||||
&main,
|
||||
source.replace("dever-worker/helper", "example.com/unlocked"),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(
|
||||
prepare()
|
||||
.err()
|
||||
.expect("unlocked import was accepted")
|
||||
.contains("locked module graph")
|
||||
);
|
||||
fs::write(&main, format!("//go:build windows\n{source}")).unwrap();
|
||||
assert!(
|
||||
prepare()
|
||||
.err()
|
||||
.expect("excluded entry was accepted")
|
||||
.contains("excluded by target")
|
||||
);
|
||||
fs::write(&main, &source).unwrap();
|
||||
for import in ["internal/abi", "dever-worker/helper/internal/value"] {
|
||||
fs::write(
|
||||
&main,
|
||||
source.replace("_ \"embed\"", &format!("_ \"embed\"; _ {import:?}")),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(
|
||||
prepare()
|
||||
.err()
|
||||
.expect("private import was accepted")
|
||||
.contains("Go internal import")
|
||||
);
|
||||
}
|
||||
fs::write(&main, &source).unwrap();
|
||||
fixture::write(
|
||||
&root,
|
||||
"module/demo/value/worker/cgo.go",
|
||||
"package main\nimport \"C\"\n",
|
||||
);
|
||||
assert!(prepare().is_err());
|
||||
fs::remove_file(root.join("module/demo/value/worker/cgo.go")).unwrap();
|
||||
let descriptor: Descriptor = serde_json::from_value(fixture.descriptor.clone()).unwrap();
|
||||
let mut missing = fixture.files.clone();
|
||||
missing.remove("stdlib/runtime.a");
|
||||
assert!(descriptor.validate(&missing, target).is_err());
|
||||
let mut missing = fixture.files.clone();
|
||||
missing.remove("bin/compile");
|
||||
assert!(descriptor.validate(&missing, target).is_err());
|
||||
let mut version = descriptor.clone();
|
||||
let actual = version.go_version.split_whitespace().nth(2).unwrap();
|
||||
version.go_version = version.go_version.replace(actual, "go0.0.0");
|
||||
assert!(
|
||||
version
|
||||
.validate(&fixture.files, target)
|
||||
.unwrap_err()
|
||||
.contains("archive target/compiler version differs")
|
||||
);
|
||||
let mut wrong = fixture.descriptor.clone();
|
||||
wrong["goarch"] = "unsupported".into();
|
||||
assert!(
|
||||
serde_json::from_value::<Descriptor>(wrong)
|
||||
.unwrap()
|
||||
.validate(&fixture.files, target)
|
||||
.is_err()
|
||||
);
|
||||
fs::remove_dir_all(root.join("module")).unwrap();
|
||||
fs::remove_dir_all(fixture.root.join("installation")).unwrap();
|
||||
for _ in 0..2 {
|
||||
let output = Command::new(&binary)
|
||||
.env_clear()
|
||||
.args(["demo.value.value", "{}"])
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"{}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
assert_eq!(
|
||||
output.stdout,
|
||||
b"{\"code\":0,\"message\":\"ok\",\"data\":42}\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user