26382a7ac6
CI / Clippy (push) Failing after 15m13s
CI / Test (ubuntu-latest) (push) Failing after 16m1s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (no embeddings / no ORT) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Cookbook (Node) (push) Has been cancelled
CI / Pi Extension (Node) (push) Has been cancelled
CI / Rust SDK (lean-ctx-client) (push) Has been cancelled
CI / Embed SDK (lean-ctx-sdk) (push) Has been cancelled
CI / Python SDK (leanctx) (push) Has been cancelled
CI / Hermes Plugin (Python) (push) Has been cancelled
CI / SDK Conformance Matrix (push) Has been cancelled
CI / Coverage (push) Has been cancelled
CI / cargo-deny (push) Has been cancelled
CI / Adversarial Safety (push) Has been cancelled
CI / Benchmarks (push) Has been cancelled
CI / Output-Quality Gate (eval A/B) (push) Has been cancelled
CI / Documentation (push) Has been cancelled
CI / CI Green (push) Has been cancelled
JetBrains Plugin / Actionlint (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (rust) (push) Has been cancelled
JetBrains Plugin / Validation (push) Has been cancelled
JetBrains Plugin / Build (push) Has been cancelled
JetBrains Plugin / Test (push) Has been cancelled
Security Check / Security Scan (push) Has been cancelled
83 lines
2.8 KiB
Rust
83 lines
2.8 KiB
Rust
//! Binds the public `OpenAPI` surface (`core::openapi::endpoints`) to the
|
|
//! Endpoints table in `docs/contracts/http-mcp-contract-v1.md`. Adding or
|
|
//! removing a public route must touch both, or this fails (EPIC 12.1).
|
|
|
|
use std::collections::BTreeSet;
|
|
use std::path::PathBuf;
|
|
|
|
/// Parse `(METHOD, /path)` pairs from the first markdown table under the
|
|
/// `## Endpoints` heading. Skips the header/separator rows and the `/*`
|
|
/// MCP fallback (it is not an `OpenAPI` path).
|
|
fn documented_pairs(doc: &str) -> BTreeSet<(String, String)> {
|
|
let mut out = BTreeSet::new();
|
|
let mut in_section = false;
|
|
for line in doc.lines() {
|
|
if line.starts_with("## ") {
|
|
if line.trim() == "## Endpoints" {
|
|
in_section = true;
|
|
continue;
|
|
} else if in_section {
|
|
break; // left the Endpoints section
|
|
}
|
|
}
|
|
if !in_section || !line.trim_start().starts_with('|') {
|
|
continue;
|
|
}
|
|
let cells: Vec<String> = line
|
|
.trim()
|
|
.trim_matches('|')
|
|
.split('|')
|
|
.map(|c| c.trim().to_string())
|
|
.collect();
|
|
if cells.len() < 2 {
|
|
continue;
|
|
}
|
|
let method = cells[0].to_uppercase();
|
|
let path = cells[1].trim_matches('`').trim().to_string();
|
|
if method == "METHOD" || method.starts_with("---") {
|
|
continue;
|
|
}
|
|
if !path.starts_with('/') || path.contains('*') {
|
|
continue; // header noise or the MCP fallback
|
|
}
|
|
out.insert((method, path));
|
|
}
|
|
out
|
|
}
|
|
|
|
#[test]
|
|
fn openapi_endpoints_match_contract_doc() {
|
|
let rust_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
let repo_root = rust_dir.parent().unwrap_or(&rust_dir);
|
|
let doc_path = repo_root.join("docs/contracts/http-mcp-contract-v1.md");
|
|
|
|
let doc = match std::fs::read_to_string(&doc_path) {
|
|
Ok(c) => c,
|
|
Err(e) => {
|
|
assert!(
|
|
!repo_root.join("docs/contracts").exists(),
|
|
"missing HTTP/MCP contract at {}: {e}",
|
|
doc_path.display()
|
|
);
|
|
eprintln!("skipping: {} not present", doc_path.display());
|
|
return;
|
|
}
|
|
};
|
|
|
|
let documented = documented_pairs(&doc);
|
|
let code: BTreeSet<(String, String)> = lean_ctx::core::openapi::endpoints()
|
|
.iter()
|
|
.map(|e| (e.method.to_uppercase(), e.path.to_string()))
|
|
.collect();
|
|
|
|
assert_eq!(
|
|
code,
|
|
documented,
|
|
"OpenAPI inventory (core::openapi::endpoints) is out of sync with the \
|
|
Endpoints table in {}.\nin code only: {:?}\nin doc only: {:?}",
|
|
doc_path.display(),
|
|
code.difference(&documented).collect::<Vec<_>>(),
|
|
documented.difference(&code).collect::<Vec<_>>(),
|
|
);
|
|
}
|