Files
yvgude--lean-ctx/rust/tests/integration_tests.rs
T
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 12:35:30 +08:00

476 lines
16 KiB
Rust

use std::process::Command;
fn lean_ctx_bin() -> Command {
let mut cmd = Command::new(env!("CARGO_BIN_EXE_lean-ctx"));
cmd.current_dir(env!("CARGO_MANIFEST_DIR"));
cmd.env("LEAN_CTX_ACTIVE", "1");
cmd.env("__LEAN_CTX_SKIP_EVENTS", "1");
// These tests exercise CLI/compression behavior, not the shell allowlist
// (which has its own unit tests in shell::exec). On CI stderr is not a TTY,
// so `allowlist_must_enforce()` would block test scripts (`for`/`while`
// loops are not allowlisted) with exit 126 — hermetic warn-only keeps the
// tests pinned to what they actually assert.
cmd.env("LEAN_CTX_ALLOWLIST_WARN_ONLY", "1");
cmd
}
#[test]
fn binary_prints_version() {
let output = lean_ctx_bin()
.arg("--version")
.output()
.expect("failed to run lean-ctx");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("lean-ctx"),
"version output should contain 'lean-ctx', got: {stdout}"
);
}
#[test]
fn binary_prints_help() {
let output = lean_ctx_bin()
.arg("--help")
.output()
.expect("failed to run lean-ctx");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("Context Runtime"),
"help should contain tagline"
);
assert!(stdout.contains("lean-ctx"), "help should mention lean-ctx");
}
#[test]
fn binary_read_file() {
let output = lean_ctx_bin()
.args(["read", "Cargo.toml", "-m", "signatures"])
.output()
.expect("failed to run lean-ctx");
assert!(output.status.success(), "read should succeed");
}
#[test]
fn binary_config_shows_defaults() {
let output = lean_ctx_bin()
.arg("config")
.output()
.expect("failed to run lean-ctx");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("checkpoint_interval"),
"config should show checkpoint_interval"
);
}
#[test]
fn shell_hook_compresses_echo() {
let output = lean_ctx_bin()
.args(["-c", "echo", "hello", "world"])
.output()
.expect("failed to run lean-ctx -c");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("hello"),
"shell hook should pass through echo output"
);
}
#[test]
fn disabled_env_bypasses_compression() {
let output = Command::new(env!("CARGO_BIN_EXE_lean-ctx"))
.current_dir(env!("CARGO_MANIFEST_DIR"))
.env("LEAN_CTX_DISABLED", "1")
.env("LEAN_CTX_COMPRESS", "1")
.env("__LEAN_CTX_SKIP_EVENTS", "1")
.args(["-c", "echo", "passthrough test"])
.output()
.expect("failed to run lean-ctx with LEAN_CTX_DISABLED");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("passthrough"),
"LEAN_CTX_DISABLED should pass output through unmodified"
);
assert!(
!stdout.contains("[lean-ctx:"),
"LEAN_CTX_DISABLED should not add compression markers"
);
}
#[test]
fn help_shows_environment_section() {
let output = lean_ctx_bin()
.arg("--help")
.output()
.expect("failed to run lean-ctx");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("LEAN_CTX_DISABLED"),
"help should document LEAN_CTX_DISABLED"
);
assert!(
stdout.contains("LEAN_CTX_RAW"),
"help should document LEAN_CTX_RAW"
);
}
// ── Pipe Guard Tests ────────────────────────────────────────
#[test]
fn pipe_guard_no_compression_when_stdout_is_piped() {
if cfg!(windows) {
return;
}
let output = Command::new(env!("CARGO_BIN_EXE_lean-ctx"))
.current_dir(env!("CARGO_MANIFEST_DIR"))
.env("__LEAN_CTX_SKIP_EVENTS", "1")
.args(["-c", "echo hello world"])
.output()
.expect("failed to run lean-ctx -c with piped stdout");
let stdout = String::from_utf8_lossy(&output.stdout);
assert_eq!(
stdout.trim(),
"hello world",
"piped stdout must pass through raw output, got: {stdout}"
);
}
#[test]
fn pipe_guard_force_compress_overrides_pipe_guard() {
if cfg!(windows) {
return;
}
let output = Command::new(env!("CARGO_BIN_EXE_lean-ctx"))
.current_dir(env!("CARGO_MANIFEST_DIR"))
.env("LEAN_CTX_COMPRESS", "1")
.env("__LEAN_CTX_SKIP_EVENTS", "1")
.args(["-c", "echo hello world"])
.output()
.expect("failed to run lean-ctx -c with LEAN_CTX_COMPRESS");
assert!(
output.status.success(),
"LEAN_CTX_COMPRESS should not crash even with piped stdout"
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("hello"),
"output should contain the echoed text"
);
}
#[test]
fn pipe_guard_multiline_output_unchanged_when_piped() {
if cfg!(windows) {
return;
}
let script = "echo line1; echo line2; echo line3; echo 'result: 42'";
let output = Command::new(env!("CARGO_BIN_EXE_lean-ctx"))
.current_dir(env!("CARGO_MANIFEST_DIR"))
.env("__LEAN_CTX_SKIP_EVENTS", "1")
.args(["-c", script])
.output()
.expect("failed to run lean-ctx -c with multiline output");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("line1"), "must contain line1");
assert!(stdout.contains("line2"), "must contain line2");
assert!(stdout.contains("line3"), "must contain line3");
assert!(
stdout.contains("result: 42"),
"must preserve exact output content"
);
}
#[test]
fn pipe_guard_bash_hook_script_test() {
if cfg!(windows) {
return;
}
let binary = env!("CARGO_BIN_EXE_lean-ctx");
let script = format!(
r#"
_lc() {{
if [ -n "${{LEAN_CTX_DISABLED:-}}" ] || [ ! -t 1 ]; then
command "$@"
return
fi
'{binary}' -c "$@"
}}
# Pipe test: _lc echo should bypass lean-ctx when piped
RESULT=$(_lc echo "pipe-guard-test-value")
echo "CAPTURED:$RESULT"
"#
);
let output = Command::new("bash")
.args(["-c", &script])
.output()
.expect("failed to run bash pipe guard test");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("CAPTURED:pipe-guard-test-value"),
"pipe guard must bypass lean-ctx in command substitution, got: {stdout}"
);
}
#[test]
fn pipe_guard_bash_hook_pipe_to_sh() {
if cfg!(windows) {
return;
}
let binary = env!("CARGO_BIN_EXE_lean-ctx");
let script = format!(
r#"
_lc() {{
if [ -n "${{LEAN_CTX_DISABLED:-}}" ] || [ ! -t 1 ]; then
command "$@"
return
fi
'{binary}' -c "$@"
}}
# Simulate curl | sh: echo a script, pipe to sh
_lc echo 'echo INSTALL_SUCCESS' | sh
"#
);
let output = Command::new("bash")
.args(["-c", &script])
.output()
.expect("failed to run bash pipe-to-sh test");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("INSTALL_SUCCESS"),
"piped script must execute correctly through sh, got: {stdout}"
);
}
#[test]
fn pipe_guard_bash_hook_redirect_to_file() {
if cfg!(windows) {
return;
}
let binary = env!("CARGO_BIN_EXE_lean-ctx");
let tmp = std::env::temp_dir().join("lean-ctx-pipe-guard-test.txt");
let tmp_path = tmp.to_str().unwrap();
let script = format!(
r#"
_lc() {{
if [ -n "${{LEAN_CTX_DISABLED:-}}" ] || [ ! -t 1 ]; then
command "$@"
return
fi
'{binary}' -c "$@"
}}
_lc echo "redirect-test-value" > {tmp_path}
cat {tmp_path}
rm -f {tmp_path}
"#
);
let output = Command::new("bash")
.args(["-c", &script])
.output()
.expect("failed to run bash redirect test");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("redirect-test-value"),
"redirected output must be raw, got: {stdout}"
);
}
// ── Redirect-to-file fidelity under FORCED compression ──────
// Regression: the agent shell hook deliberately bypasses the `[ ! -t 1 ]` pipe
// guard (an agent IS the consumer), so an agent running
// `git status --short > files.txt` reached `lean-ctx -c` with stdout pointing at a
// regular FILE and forced compression on. The compressed digest was written INTO
// the file, dropping/abbreviating lines and producing contradictory diffs. Output
// redirected to a regular file must ALWAYS stay byte-faithful, even when
// compression is forced; pipes (agent capture) must keep compressing.
// >30 distinct lines so the compression engine definitely rewrites the output
// (the truncate-with-safety-scan fallback collapses the middle). This makes the
// assertions below meaningful — pre-fix, the file held the compressed digest.
// The payload must NOT contain any passthrough/verbatim keyword (notably the
// literal "lean-ctx", which classifies the whole command as Passthrough), or the
// output would never be compressed and the test would be vacuous.
fn redirect_fidelity_command() -> &'static str {
"i=0; while [ $i -lt 60 ]; do echo \"row $i alpha beta gamma delta payload\"; i=$((i+1)); done"
}
/// `lean-ctx -c` with a *hermetic* control environment for the compression
/// fidelity tests. A developer's shell hook exports `LEAN_CTX_RAW` /
/// `LEAN_CTX_DISABLED` (and CI may set `LEAN_CTX_ACTIVE`) — each forces raw
/// passthrough, which would make these tests assert nothing (the redirect test
/// would pass vacuously). Stripping them pins the exact forced-compress path.
/// `LEAN_CTX_WRAPPED` must go too: running `cargo test` *through* the lean-ctx
/// wrapper stamps it on every child, and the nested `lean-ctx -c` under test
/// would then (correctly) defer to the parent instead of compressing.
fn forced_compress_bin() -> Command {
let mut cmd = Command::new(env!("CARGO_BIN_EXE_lean-ctx"));
cmd.current_dir(env!("CARGO_MANIFEST_DIR"))
.env_remove("LEAN_CTX_RAW")
.env_remove("LEAN_CTX_DISABLED")
.env_remove("LEAN_CTX_ACTIVE")
.env_remove("LEAN_CTX_WRAPPED")
.env("LEAN_CTX_COMPRESS", "1")
.env("__LEAN_CTX_SKIP_EVENTS", "1")
// Allowlist enforcement (non-TTY stderr ⇒ block) is out of scope here;
// the fidelity scripts use `while` loops that are not allowlisted.
.env("LEAN_CTX_ALLOWLIST_WARN_ONLY", "1");
cmd
}
#[test]
fn force_compress_redirect_to_file_is_byte_faithful() {
if cfg!(windows) {
return;
}
let cmd = redirect_fidelity_command();
// Ground truth: the raw command output (no lean-ctx in the loop).
let raw = Command::new("sh")
.args(["-c", cmd])
.output()
.expect("failed to run raw command");
let raw_stdout = String::from_utf8_lossy(&raw.stdout).to_string();
// Run lean-ctx with forced compression, stdout redirected to a real file —
// exactly the agent `cmd > file` scenario.
let tmp = std::env::temp_dir().join(format!(
"lean-ctx-redirect-fidelity-{}.txt",
std::process::id()
));
let file = std::fs::File::create(&tmp).expect("create temp file");
let status = forced_compress_bin()
.args(["-c", cmd])
.stdout(std::process::Stdio::from(file))
.status()
.expect("failed to run lean-ctx -c with file redirect");
assert!(status.success(), "lean-ctx -c should exit cleanly");
let file_content = std::fs::read_to_string(&tmp).expect("read temp file");
let _ = std::fs::remove_file(&tmp);
assert_eq!(
file_content, raw_stdout,
"redirect to a regular file under LEAN_CTX_COMPRESS must be byte-faithful (never compressed)"
);
}
#[test]
fn force_compress_pipe_still_compresses() {
// Companion to the redirect test: proves compression is genuinely active for
// the SAME command + env when stdout is a PIPE (an agent's capture). If this
// ever stops compressing, the redirect test above would be vacuous.
if cfg!(windows) {
return;
}
let cmd = redirect_fidelity_command();
let raw = Command::new("sh")
.args(["-c", cmd])
.output()
.expect("failed to run raw command");
let raw_stdout = String::from_utf8_lossy(&raw.stdout).to_string();
let piped = forced_compress_bin()
.args(["-c", cmd])
.output()
.expect("failed to run lean-ctx -c with piped stdout");
let piped_stdout = String::from_utf8_lossy(&piped.stdout).to_string();
assert_ne!(
piped_stdout, raw_stdout,
"piped stdout under LEAN_CTX_COMPRESS should be compressed (changed) — proves the redirect guard is meaningful"
);
}
// ── Extended CLI Smoke Tests ────────────────────────────────
#[test]
fn binary_gain_json_returns_valid_json() {
let output = lean_ctx_bin()
.args(["gain", "--json"])
.output()
.expect("failed to run lean-ctx gain --json");
assert!(output.status.success(), "gain --json should succeed");
let stdout = String::from_utf8_lossy(&output.stdout);
let parsed: Result<serde_json::Value, _> = serde_json::from_str(stdout.trim());
assert!(
parsed.is_ok(),
"gain --json should return valid JSON, got: {stdout}"
);
}
#[test]
fn binary_grep_finds_matches() {
let output = lean_ctx_bin()
.args(["grep", "fn main", "src/"])
.output()
.expect("failed to run lean-ctx grep");
assert!(
output.status.success(),
"grep should succeed (exit={})",
output.status.code().unwrap_or(-1)
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("main") || stdout.contains("fn"),
"grep should find matches: {stdout}"
);
}
#[test]
fn binary_ls_shows_tree() {
let output = lean_ctx_bin()
.args(["ls", "--depth", "2"])
.output()
.expect("failed to run lean-ctx ls");
assert!(
output.status.success(),
"ls should succeed (exit={})",
output.status.code().unwrap_or(-1)
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("src") || stdout.contains("Cargo"),
"ls should show directory tree: {stdout}"
);
}
#[test]
fn binary_doctor_runs_without_crash() {
let output = lean_ctx_bin()
.arg("doctor")
.output()
.expect("failed to run lean-ctx doctor");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("lean-ctx")
|| stdout.contains("doctor")
|| stdout.contains("✓")
|| stdout.contains("check"),
"doctor should produce diagnostic output: {stdout}"
);
}
#[test]
fn pipe_guard_rust_side_defense_in_depth() {
if cfg!(windows) {
return;
}
let script = "for i in 1 2 3 4 5; do echo \"item_$i: $(date +%s)\"; done";
let output = Command::new(env!("CARGO_BIN_EXE_lean-ctx"))
.current_dir(env!("CARGO_MANIFEST_DIR"))
.env("__LEAN_CTX_SKIP_EVENTS", "1")
// `for` + command substitution are not allowlisted; this test pins the
// pipe guard, not enforcement (covered by shell::exec unit tests).
.env("LEAN_CTX_ALLOWLIST_WARN_ONLY", "1")
.args(["-c", script])
.output()
.expect("failed to run lean-ctx -c");
let stdout = String::from_utf8_lossy(&output.stdout);
for i in 1..=5 {
assert!(
stdout.contains(&format!("item_{i}:")),
"Rust-side pipe guard must pass through all lines unchanged (missing item_{i})"
);
}
}