118 lines
3.7 KiB
Rust
118 lines
3.7 KiB
Rust
use std::collections::BTreeSet;
|
|
use std::fs;
|
|
use std::path::{Path, PathBuf};
|
|
|
|
const ALLOWED_DEPENDENCIES: [&str; 8] = [
|
|
"libremetaverse",
|
|
"libremetaverse-types",
|
|
"reqwest",
|
|
"serde",
|
|
"serde_json",
|
|
"sha2",
|
|
"tokio",
|
|
"url",
|
|
];
|
|
|
|
#[test]
|
|
fn package_has_only_reviewed_rust_dependencies_and_no_build_script() {
|
|
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
assert!(
|
|
!root.join("build.rs").exists(),
|
|
"agent must not have a build script"
|
|
);
|
|
let manifest = fs::read_to_string(root.join("Cargo.toml")).expect("read package manifest");
|
|
let dependency_section = manifest
|
|
.split("[dependencies]")
|
|
.nth(1)
|
|
.expect("dependency section")
|
|
.split("\n[")
|
|
.next()
|
|
.expect("end of dependency section");
|
|
let observed = dependency_section
|
|
.lines()
|
|
.filter_map(|line| line.split_once('=').map(|(name, _)| name.trim()))
|
|
.filter(|name| !name.is_empty())
|
|
.collect::<BTreeSet<_>>();
|
|
assert_eq!(
|
|
observed,
|
|
ALLOWED_DEPENDENCIES.into_iter().collect(),
|
|
"every direct dependency needs explicit policy review"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn runtime_source_has_no_subprocess_or_native_abi_escape_hatch() {
|
|
let source = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("src");
|
|
let mut files = Vec::with_capacity(8);
|
|
collect_rust_files(&source, &mut files);
|
|
assert!(
|
|
files.len() <= 12,
|
|
"source-file count needs a reviewed bound update"
|
|
);
|
|
for path in files {
|
|
let text = fs::read_to_string(&path).expect("read runtime source");
|
|
for forbidden in [
|
|
"std::process::Command",
|
|
"tokio::process",
|
|
"Command::new(",
|
|
"extern \"C\"",
|
|
"#[link(",
|
|
"unsafe fn ",
|
|
"unsafe impl ",
|
|
] {
|
|
assert!(
|
|
!text.contains(forbidden),
|
|
"{} contains forbidden runtime boundary {forbidden:?}",
|
|
path.display()
|
|
);
|
|
}
|
|
assert!(
|
|
!text.lines().any(|line| {
|
|
let line = line.trim_start();
|
|
line.starts_with("unsafe {") || line.contains("= unsafe {")
|
|
}),
|
|
"{} contains an unsafe block",
|
|
path.display()
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn world_backend_requires_the_opaque_policy_authorization() {
|
|
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
let backend = fs::read_to_string(root.join("src/backend.rs")).expect("backend source");
|
|
assert!(backend.contains("action: AuthorizedAction"));
|
|
assert!(!backend.contains("call: ProposedToolCall"));
|
|
assert!(!backend.contains("decision: PolicyDecision"));
|
|
}
|
|
|
|
#[test]
|
|
fn live_session_adapter_reuses_only_the_native_network_manager_lifecycle() {
|
|
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
let backend = fs::read_to_string(root.join("src/backend.rs")).expect("backend source");
|
|
for required in [
|
|
".native_default_login_params(",
|
|
".native_login(",
|
|
".native_subscribe_disconnected(",
|
|
".native_subscribe_event_queue_running(",
|
|
".native_logout_async(",
|
|
] {
|
|
assert!(
|
|
backend.contains(required),
|
|
"missing native lifecycle {required}"
|
|
);
|
|
}
|
|
assert!(!backend.contains("reqwest"));
|
|
}
|
|
|
|
fn collect_rust_files(directory: &Path, output: &mut Vec<PathBuf>) {
|
|
for entry in fs::read_dir(directory).expect("read source directory") {
|
|
let path = entry.expect("source entry").path();
|
|
if path.is_dir() {
|
|
collect_rust_files(&path, output);
|
|
} else if path.extension().is_some_and(|extension| extension == "rs") {
|
|
output.push(path);
|
|
}
|
|
}
|
|
}
|