use std::path::{Path, PathBuf};
const FORBIDDEN_PATTERNS: &[&str] = &[
"MergeInsertBuilder",
"InsertBuilder::",
"DeleteBuilder",
"CommitBuilder::new",
".create_index_builder(",
".create_index_segment_builder(",
"Dataset::write",
"Dataset::append",
"Dataset::delete",
"Dataset::merge_insert",
"Dataset::add_columns",
"Dataset::update_columns",
"Dataset::drop_columns",
"Dataset::truncate_table",
"Dataset::restore",
".merge_insert(",
".add_columns(",
".update_columns(",
".drop_columns(",
".truncate_table(",
".restore(",
];
const ALLOW_LIST_FILES: &[&str] = &[
"table_store.rs", "storage_layer.rs", "commit_graph.rs", "graph_coordinator.rs", "recovery_audit.rs", ];
const ALLOW_LIST_DIRS: &[&str] = &[
"db/manifest", "db/manifest/", ];
const SENTINEL: &str = "// forbidden-api-allow:";
fn engine_src_root() -> PathBuf {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR");
PathBuf::from(manifest_dir).join("src")
}
fn is_allow_listed(path: &Path) -> bool {
let path_str = path.to_string_lossy();
if let Some(name) = path.file_name().and_then(|s| s.to_str()) {
if ALLOW_LIST_FILES.iter().any(|f| *f == name) {
return true;
}
}
ALLOW_LIST_DIRS.iter().any(|d| path_str.contains(d))
}
fn walk_rust_files(root: &Path) -> Vec<PathBuf> {
let mut out = Vec::new();
walk_into(root, &mut out);
out
}
fn walk_into(dir: &Path, out: &mut Vec<PathBuf>) {
let entries = match std::fs::read_dir(dir) {
Ok(e) => e,
Err(_) => return,
};
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
walk_into(&path, out);
} else if path.extension().and_then(|s| s.to_str()) == Some("rs") {
out.push(path);
}
}
}
#[test]
fn engine_code_does_not_call_forbidden_lance_apis() {
let src = engine_src_root();
let mut violations = Vec::new();
for file in walk_rust_files(&src) {
if is_allow_listed(&file) {
continue;
}
let contents = match std::fs::read_to_string(&file) {
Ok(c) => c,
Err(_) => continue,
};
let lines: Vec<&str> = contents.lines().collect();
for (idx, line) in lines.iter().enumerate() {
let trimmed = line.trim_start();
if trimmed.starts_with("//")
|| trimmed.starts_with("/*")
|| trimmed.starts_with("*")
{
continue;
}
if line.contains(SENTINEL) {
continue;
}
if idx > 0 && lines[idx - 1].contains(SENTINEL) {
continue;
}
for pattern in FORBIDDEN_PATTERNS {
if line.contains(pattern) {
let rel = file
.strip_prefix(&src)
.unwrap_or(&file)
.display()
.to_string();
violations.push(format!(
"{}:{}: forbidden pattern `{}` — {}",
rel,
idx + 1,
pattern,
line.trim()
));
}
}
}
}
if !violations.is_empty() {
panic!(
"Forbidden-API guard found {} violation(s) in engine code. \
Engine code MUST route through the `TableStorage` trait (or its \
inherent counterparts on `TableStore`) instead of calling Lance's \
inline-commit APIs directly. If a use is genuinely justified, add \
the comment `// forbidden-api-allow: <reason>` on the same line or \
the line above.\n\nViolations:\n {}",
violations.len(),
violations.join("\n ")
);
}
}