feat: publish Dever core with project scaffolding and versioned AI skills
This commit is contained in:
1 parent
70fa73cdc2
commit
ac458ffa7f
960 files changed
+221319
-1163
No files matched your search
@@ -0,0 +1,2 @@
|
||||
/* Deliberately separate DT_NEEDED dependency for native command packaging. */
|
||||
int command_value(void) { return 42; }
|
||||
@@ -0,0 +1,19 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
extern int command_value(void);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const unsigned char expected[] = {0, 255, 128, 10};
|
||||
unsigned char input[sizeof(expected)];
|
||||
if (argc != 3 || strcmp(argv[1], "a b") != 0 ||
|
||||
strcmp(argv[2], "$(literal);*") != 0 || command_value() != 42)
|
||||
return 90;
|
||||
if (fread(input, 1, sizeof(input), stdin) != sizeof(input) ||
|
||||
memcmp(input, expected, sizeof(input)) != 0 || getchar() != EOF)
|
||||
return 91;
|
||||
if (fwrite(input, 1, sizeof(input), stdout) != sizeof(input) ||
|
||||
fputs("ordinary command", stderr) == EOF)
|
||||
return 92;
|
||||
return 23;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/* Native author fixture for compile cancellation and deadline supervision. */
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc == 2 && strcmp(argv[1], "--dever-health") == 0) return 0;
|
||||
FILE *pid = fopen("worker.pid", "w");
|
||||
if (!pid) return 2;
|
||||
if (fprintf(pid, "%ld", (long)getpid()) < 0 || fclose(pid) != 0) return 3;
|
||||
struct timespec remaining = {300, 0};
|
||||
while (nanosleep(&remaining, &remaining) != 0) {
|
||||
if (errno != EINTR) return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
//! Lifetime of an explicitly requested test-owned shared compiler service.
|
||||
use std::process::{Child, Command};
|
||||
use std::time::Duration;
|
||||
|
||||
use dever_cli::toolchain::{Layout, cache_status};
|
||||
|
||||
pub struct TestDaemon(Child);
|
||||
|
||||
impl TestDaemon {
|
||||
pub fn start(layout: &Layout) -> Self {
|
||||
let child = Command::new(env!("CARGO_BIN_EXE_deverd"))
|
||||
.env_clear()
|
||||
.current_dir(layout.root())
|
||||
.args(["--root", "."])
|
||||
.spawn()
|
||||
.unwrap();
|
||||
let mut daemon = Self(child);
|
||||
for _ in 0..100 {
|
||||
if cache_status(layout).is_ok() {
|
||||
return daemon;
|
||||
}
|
||||
assert!(
|
||||
daemon.0.try_wait().unwrap().is_none(),
|
||||
"test deverd exited early"
|
||||
);
|
||||
std::thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
panic!("test deverd did not become ready");
|
||||
}
|
||||
|
||||
pub fn stop(&mut self) {
|
||||
self.0.kill().unwrap();
|
||||
self.0.wait().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TestDaemon {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.0.kill();
|
||||
let _ = self.0.wait();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
//! Explicit Linux author inputs shared by opt-in native fixtures.
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub const LLVM_LIBRARY: &str = "/usr/lib/llvm-18/lib/libLLVM.so.1";
|
||||
|
||||
pub fn core_libraries() -> Vec<(&'static str, PathBuf)> {
|
||||
let mut inputs = vec![("libLLVM.so.18.1", PathBuf::from(LLVM_LIBRARY))];
|
||||
for name in [
|
||||
"libstdc++.so.6",
|
||||
"libgcc_s.so.1",
|
||||
"libz.so.1",
|
||||
"libffi.so.8",
|
||||
"libedit.so.2",
|
||||
"libzstd.so.1",
|
||||
"libtinfo.so.6",
|
||||
"libxml2.so.2",
|
||||
"libbsd.so.0",
|
||||
"libmd.so.0",
|
||||
"libicuuc.so.74",
|
||||
"libicudata.so.74",
|
||||
"liblzma.so.5",
|
||||
] {
|
||||
inputs.push((name, Path::new("/usr/lib/x86_64-linux-gnu").join(name)));
|
||||
}
|
||||
inputs
|
||||
.into_iter()
|
||||
.map(|(name, path)| {
|
||||
(
|
||||
name,
|
||||
path.canonicalize()
|
||||
.expect("prepare the explicit GNU compiler-library inputs"),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn native_inputs() -> Vec<(&'static str, PathBuf)> {
|
||||
let workspace = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
|
||||
vec![
|
||||
(
|
||||
"runtime.a",
|
||||
workspace.join("target/native-runtime-abi/debug/libdever_backend_bridge.a"),
|
||||
),
|
||||
("crt1.o", "/usr/lib/x86_64-linux-gnu/crt1.o".into()),
|
||||
("crti.o", "/usr/lib/x86_64-linux-gnu/crti.o".into()),
|
||||
(
|
||||
"crtbeginT.o",
|
||||
"/usr/lib/gcc/x86_64-linux-gnu/13/crtbeginT.o".into(),
|
||||
),
|
||||
(
|
||||
"crtend.o",
|
||||
"/usr/lib/gcc/x86_64-linux-gnu/13/crtend.o".into(),
|
||||
),
|
||||
("crtn.o", "/usr/lib/x86_64-linux-gnu/crtn.o".into()),
|
||||
("libc.a", "/usr/lib/x86_64-linux-gnu/libc.a".into()),
|
||||
("libm.a", "/usr/lib/x86_64-linux-gnu/libm-2.39.a".into()),
|
||||
("libmvec.a", "/usr/lib/x86_64-linux-gnu/libmvec.a".into()),
|
||||
(
|
||||
"libgcc.a",
|
||||
"/usr/lib/gcc/x86_64-linux-gnu/13/libgcc.a".into(),
|
||||
),
|
||||
(
|
||||
"libgcc_eh.a",
|
||||
"/usr/lib/gcc/x86_64-linux-gnu/13/libgcc_eh.a".into(),
|
||||
),
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
//! Explicit test inputs: no downloads, recursive builds or host tool lookup.
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use dever_cli::toolchain::sha256_file as hash_file;
|
||||
use serde_json::{Value, json};
|
||||
|
||||
#[path = "llvm_inputs.rs"]
|
||||
mod inputs;
|
||||
#[cfg(test)]
|
||||
#[path = "native_objects.rs"]
|
||||
mod native_objects;
|
||||
use inputs::{core_libraries, native_inputs};
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn compiler(source: &Path, root: &Path, name: &str) -> PathBuf {
|
||||
fs::create_dir_all(root).unwrap();
|
||||
let path = root.join(name);
|
||||
fs::hard_link(source, &path).unwrap();
|
||||
compiler_library(root).unwrap();
|
||||
path
|
||||
}
|
||||
|
||||
pub fn pack_root(root: &Path) -> PathBuf {
|
||||
root.join("runtime")
|
||||
.join(dever_cli::toolchain::platform_identity())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn manifest(root: &Path, real: bool) -> Value {
|
||||
let destination = pack_root(root);
|
||||
fs::create_dir_all(&destination).unwrap();
|
||||
let sources = native_inputs();
|
||||
let mut files = Vec::new();
|
||||
for (name, source) in sources {
|
||||
let output = destination.join(name);
|
||||
if real {
|
||||
assert!(
|
||||
source.is_file(),
|
||||
"prepare the explicit native archive and CRT fixture first: {}",
|
||||
source.display()
|
||||
);
|
||||
// Only immutable reads follow. Corruption cases use synthetic files.
|
||||
fs::hard_link(source, &output).unwrap();
|
||||
} else {
|
||||
fs::write(
|
||||
&output,
|
||||
if name.ends_with(".a") {
|
||||
native_objects::archive(
|
||||
dever_cli::toolchain::BuildTarget::host().unwrap(),
|
||||
"fixture.o",
|
||||
)
|
||||
} else {
|
||||
native_objects::object(dever_cli::toolchain::BuildTarget::host().unwrap())
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
files.push(json!({"path":name, "bytes":fs::metadata(&output).unwrap().len(), "sha256":digest(&output)}));
|
||||
}
|
||||
let document = document(files);
|
||||
write_manifest(root, &document);
|
||||
document
|
||||
}
|
||||
|
||||
fn document(files: Vec<Value>) -> Value {
|
||||
let profile = json!({
|
||||
"start":["crt1.o","crti.o","crtbeginT.o"], "runtime":"runtime.a",
|
||||
"libraries":["libc.a","libm.a","libmvec.a","libgcc.a","libgcc_eh.a"],
|
||||
"end":["crtend.o","crtn.o"]
|
||||
});
|
||||
json!({
|
||||
"format":"dever-native-runtime-v1", "compiler_version":env!("CARGO_PKG_VERSION"),
|
||||
"abi":dever_backend_bridge::RUNTIME_ABI_VERSION,
|
||||
"platform":dever_cli::toolchain::platform_identity(),
|
||||
"target":"x86_64-unknown-linux-gnu",
|
||||
"profiles":{"base":profile,"sqlite":profile,"postgres":profile,"both":profile},
|
||||
"files":files
|
||||
})
|
||||
}
|
||||
|
||||
fn compiler_library(root: &Path) -> Result<(), String> {
|
||||
let libraries = root.join("lib");
|
||||
create_or_check_directory(&libraries)?;
|
||||
for (name, source) in core_libraries() {
|
||||
let target = libraries.join(name);
|
||||
match fs::symlink_metadata(&target) {
|
||||
Ok(metadata) if metadata.is_file() && !metadata.file_type().is_symlink() => {
|
||||
if hash_file(&target)? != hash_file(&source)? {
|
||||
return Err(
|
||||
"existing compiler library differs from the explicit author SDK".into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(_) => return Err("compiler library must be a real file".into()),
|
||||
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
|
||||
fs::hard_link(source, target).map_err(|error| error.to_string())?;
|
||||
}
|
||||
Err(error) => return Err(error.to_string()),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_or_check_directory(path: &Path) -> Result<(), String> {
|
||||
match fs::symlink_metadata(path) {
|
||||
Ok(metadata) if metadata.is_dir() && !metadata.file_type().is_symlink() => Ok(()),
|
||||
Ok(_) => Err(format!("'{}' must be a real directory", path.display())),
|
||||
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
|
||||
fs::create_dir(path).map_err(|error| error.to_string())
|
||||
}
|
||||
Err(error) => Err(error.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn write_manifest(root: &Path, manifest: &Value) {
|
||||
fs::write(
|
||||
pack_root(root).join("manifest.json"),
|
||||
serde_json::to_vec(manifest).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn digest(path: &Path) -> String {
|
||||
hash_file(path).unwrap()
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//! Test-only static entry for the already pivoted no-host acceptance namespace.
|
||||
#[cfg(target_os = "linux")]
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
use rustix::mount::{MountFlags, mount};
|
||||
use rustix::thread::{self, CapabilitySet};
|
||||
use std::os::unix::process::CommandExt;
|
||||
|
||||
let mut arguments = std::env::args_os().skip(1);
|
||||
let executable = arguments.next().ok_or("missing acceptance executable")?;
|
||||
if !std::path::Path::new(&executable).is_absolute() {
|
||||
return Err("acceptance executable must be absolute".into());
|
||||
}
|
||||
// The root-only harness keeps bwrap's original namespace capabilities.
|
||||
// Reject ordinary host execution before touching any mount.
|
||||
if !thread::no_new_privs()?
|
||||
|| !thread::capabilities(None)?
|
||||
.effective
|
||||
.contains(CapabilitySet::SYS_ADMIN)
|
||||
{
|
||||
return Err("acceptance init requires its restricted fixture namespace".into());
|
||||
}
|
||||
// bwrap's readonly proc submounts otherwise prevent a nested user
|
||||
// namespace from mounting its own proc. Replace only this private proc.
|
||||
mount(
|
||||
"proc",
|
||||
"/proc",
|
||||
"proc",
|
||||
MountFlags::NOSUID | MountFlags::NODEV | MountFlags::NOEXEC,
|
||||
None,
|
||||
)?;
|
||||
Err(std::process::Command::new(executable)
|
||||
.args(arguments)
|
||||
.env_clear()
|
||||
.exec()
|
||||
.into())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn main() -> Result<(), &'static str> {
|
||||
Err("native acceptance isolation requires Linux")
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
//! Small ELF metadata fixtures; execution acceptance uses real author inputs.
|
||||
pub fn compiler(needed: &[&str]) -> Vec<u8> {
|
||||
elf(None, needed, Some("$ORIGIN/lib"))
|
||||
}
|
||||
|
||||
pub fn library(name: &str, needed: &[&str]) -> Vec<u8> {
|
||||
elf(Some(name), needed, None)
|
||||
}
|
||||
|
||||
pub fn static_executable() -> Vec<u8> {
|
||||
let mut bytes = elf(None, &[], None);
|
||||
// Change the synthetic PT_INTERP entry to PT_NULL. Execution tests use the
|
||||
// real static author input; this fixture tests only ELF admission rules.
|
||||
bytes[64 + 2 * 56..68 + 2 * 56].copy_from_slice(&0u32.to_le_bytes());
|
||||
bytes
|
||||
}
|
||||
|
||||
pub fn elf(soname: Option<&str>, needed: &[&str], rpath: Option<&str>) -> Vec<u8> {
|
||||
let mut strings = vec![0u8];
|
||||
let mut string = |text: &str| {
|
||||
let offset = strings.len() as u64;
|
||||
strings.extend_from_slice(text.as_bytes());
|
||||
strings.push(0);
|
||||
offset
|
||||
};
|
||||
let mut dynamic = needed
|
||||
.iter()
|
||||
.map(|name| (1u64, string(name)))
|
||||
.collect::<Vec<_>>();
|
||||
if let Some(name) = soname {
|
||||
dynamic.push((14, string(name)));
|
||||
}
|
||||
if let Some(path) = rpath {
|
||||
dynamic.push((15, string(path)));
|
||||
}
|
||||
let interpreter = if cfg!(target_arch = "aarch64") {
|
||||
b"/lib/ld-linux-aarch64.so.1\0".as_slice()
|
||||
} else {
|
||||
b"/lib64/ld-linux-x86-64.so.2\0".as_slice()
|
||||
};
|
||||
let header_count: u16 = if soname.is_some() { 2 } else { 3 };
|
||||
let string_offset = 64 + usize::from(header_count) * 56;
|
||||
let interpreter_offset = string_offset + strings.len();
|
||||
let dynamic_offset = (interpreter_offset + interpreter.len() + 7) & !7;
|
||||
dynamic.extend([
|
||||
(5, string_offset as u64),
|
||||
(10, strings.len() as u64),
|
||||
(0, 0),
|
||||
]);
|
||||
let length = dynamic_offset + dynamic.len() * 16;
|
||||
let mut bytes = vec![0; length];
|
||||
bytes[..7].copy_from_slice(b"\x7fELF\x02\x01\x01");
|
||||
bytes[16..18].copy_from_slice(&3u16.to_le_bytes());
|
||||
let machine = if cfg!(target_arch = "aarch64") {
|
||||
183u16
|
||||
} else {
|
||||
62u16
|
||||
};
|
||||
bytes[18..20].copy_from_slice(&machine.to_le_bytes());
|
||||
bytes[20..24].copy_from_slice(&1u32.to_le_bytes());
|
||||
bytes[32..40].copy_from_slice(&64u64.to_le_bytes());
|
||||
bytes[52..54].copy_from_slice(&64u16.to_le_bytes());
|
||||
bytes[54..56].copy_from_slice(&56u16.to_le_bytes());
|
||||
bytes[56..58].copy_from_slice(&header_count.to_le_bytes());
|
||||
let mut segment = |index: usize, kind: u32, offset: usize, size: usize| {
|
||||
let start = 64 + index * 56;
|
||||
bytes[start..start + 4].copy_from_slice(&kind.to_le_bytes());
|
||||
bytes[start + 4..start + 8].copy_from_slice(&4u32.to_le_bytes());
|
||||
for at in [8, 16, 24] {
|
||||
bytes[start + at..start + at + 8].copy_from_slice(&(offset as u64).to_le_bytes());
|
||||
}
|
||||
for at in [32, 40] {
|
||||
bytes[start + at..start + at + 8].copy_from_slice(&(size as u64).to_le_bytes());
|
||||
}
|
||||
bytes[start + 48..start + 56].copy_from_slice(&1u64.to_le_bytes());
|
||||
};
|
||||
segment(0, 1, 0, length);
|
||||
segment(1, 2, dynamic_offset, dynamic.len() * 16);
|
||||
if soname.is_none() {
|
||||
segment(2, 3, interpreter_offset, interpreter.len());
|
||||
}
|
||||
bytes[string_offset..interpreter_offset].copy_from_slice(&strings);
|
||||
bytes[interpreter_offset..interpreter_offset + interpreter.len()].copy_from_slice(interpreter);
|
||||
for (index, (tag, value)) in dynamic.into_iter().enumerate() {
|
||||
let start = dynamic_offset + index * 16;
|
||||
bytes[start..start + 8].copy_from_slice(&tag.to_le_bytes());
|
||||
bytes[start + 8..start + 16].copy_from_slice(&value.to_le_bytes());
|
||||
}
|
||||
bytes
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//! Small architecture-bearing link inputs for pack validation tests.
|
||||
use dever_cli::toolchain::BuildTarget;
|
||||
|
||||
pub fn object(target: BuildTarget) -> Vec<u8> {
|
||||
let mut bytes = vec![0; 64];
|
||||
bytes[..7].copy_from_slice(b"\x7fELF\x02\x01\x01");
|
||||
bytes[16..18].copy_from_slice(&1_u16.to_le_bytes());
|
||||
let machine: u16 = match target {
|
||||
BuildTarget::LinuxX86_64 => 62,
|
||||
BuildTarget::LinuxAarch64 => 183,
|
||||
};
|
||||
bytes[18..20].copy_from_slice(&machine.to_le_bytes());
|
||||
bytes
|
||||
}
|
||||
|
||||
pub fn archive(target: BuildTarget, member: &str) -> Vec<u8> {
|
||||
let object = object(target);
|
||||
let header = format!(
|
||||
"{:<16}{:<12}{:<6}{:<6}{:<8}{:<10}`\n",
|
||||
format!("{member}/"),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"644",
|
||||
object.len()
|
||||
);
|
||||
assert_eq!(header.len(), 60);
|
||||
[b"!<arch>\n".as_slice(), header.as_bytes(), &object].concat()
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
use std::io::{Cursor, Write};
|
||||
|
||||
use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD};
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
pub fn metadata(name: &str, version: &str, requires: &[&str], extras: &[&str]) -> String {
|
||||
let mut text = format!("Metadata-Version: 2.4\nName: {name}\nVersion: {version}\n");
|
||||
for requirement in requires {
|
||||
text.push_str(&format!("Requires-Dist: {requirement}\n"));
|
||||
}
|
||||
for extra in extras {
|
||||
text.push_str(&format!("Provides-Extra: {extra}\n"));
|
||||
}
|
||||
text
|
||||
}
|
||||
|
||||
pub fn pack(
|
||||
name: &str,
|
||||
version: &str,
|
||||
wheel: &str,
|
||||
metadata: &str,
|
||||
extra: &[(&str, Vec<u8>)],
|
||||
) -> Vec<u8> {
|
||||
let info = format!("{}-{version}.dist-info", name.replace('-', "_"));
|
||||
let mut files = vec![
|
||||
(format!("{info}/WHEEL"), wheel.as_bytes().to_vec()),
|
||||
(format!("{info}/METADATA"), metadata.as_bytes().to_vec()),
|
||||
];
|
||||
files.extend(
|
||||
extra
|
||||
.iter()
|
||||
.map(|(path, bytes)| ((*path).to_owned(), bytes.clone())),
|
||||
);
|
||||
let mut record = csv::WriterBuilder::new()
|
||||
.has_headers(false)
|
||||
.from_writer(Vec::new());
|
||||
for (path, bytes) in &files {
|
||||
record
|
||||
.write_record([
|
||||
path.clone(),
|
||||
format!("sha256={}", URL_SAFE_NO_PAD.encode(Sha256::digest(bytes))),
|
||||
bytes.len().to_string(),
|
||||
])
|
||||
.unwrap();
|
||||
}
|
||||
let path = format!("{info}/RECORD");
|
||||
record
|
||||
.write_record([path.clone(), String::new(), String::new()])
|
||||
.unwrap();
|
||||
files.push((path, record.into_inner().unwrap()));
|
||||
zip(&files)
|
||||
}
|
||||
|
||||
pub fn zip(files: &[(String, Vec<u8>)]) -> Vec<u8> {
|
||||
let mut writer = zip::ZipWriter::new(Cursor::new(Vec::new()));
|
||||
for (path, bytes) in files {
|
||||
writer
|
||||
.start_file(path, zip::write::SimpleFileOptions::default())
|
||||
.unwrap();
|
||||
writer.write_all(bytes).unwrap();
|
||||
}
|
||||
writer.finish().unwrap().into_inner()
|
||||
}
|
||||
|
||||
pub fn markers() -> pep508_rs::MarkerEnvironment {
|
||||
pep508_rs::MarkerEnvironmentBuilder {
|
||||
implementation_name: "cpython",
|
||||
implementation_version: "3.12.0",
|
||||
os_name: "posix",
|
||||
platform_machine: "x86_64",
|
||||
platform_python_implementation: "CPython",
|
||||
platform_release: "",
|
||||
platform_system: "Linux",
|
||||
platform_version: "",
|
||||
python_full_version: "3.12.0",
|
||||
python_version: "3.12",
|
||||
sys_platform: "linux",
|
||||
}
|
||||
.try_into()
|
||||
.unwrap()
|
||||
}
|
||||
Reference in new issue
Block a user