//! Workspace policy tests for Jade Discipline. use std::fs; use std::path::PathBuf; fn workspace_root() -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("..") .join("..") .canonicalize() .expect("workspace root") } fn workspace_path(components: &[&str]) -> PathBuf { components .iter() .fold(workspace_root(), |path, component| path.join(component)) } fn script_path(script_name: &str) -> PathBuf { workspace_path(&["scripts", script_name]) } fn read_workspace_text(components: &[&str], label: &str) -> String { fs::read_to_string(workspace_path(components)) .unwrap_or_else(|error| panic!("failed to read {label}: {error}")) } #[test] fn workspace_cargo_toml_publishes_jade_lints_and_profiles() { let cargo_toml = read_workspace_text(&["Cargo.toml"], "Cargo.toml"); for required_line in [ "rust-version = \"1.86\"", "missing_docs = \"deny\"", "pedantic = { level = \"deny\", priority = -3 }", "nursery = { level = \"deny\", priority = -2 }", "[profile.release-fast]", "lto = \"fat\"", "[profile.release-size]", "opt-level = \"z\"", ] { assert!( cargo_toml.contains(required_line), "Cargo.toml should contain {required_line:?}" ); } for forbidden_line in [ "missing_copy_implementations", "implicit_return", "missing_const_for_fn", "module_name_repetitions", "multiple_crate_versions", "must_use_candidate", "needless_pass_by_value", ] { assert!( !cargo_toml.contains(forbidden_line), "Cargo.toml should not contain {forbidden_line:?}" ); } } #[test] fn cargo_config_and_jade_docs_exist() { let config = read_workspace_text(&[".cargo", "config.toml"], ".cargo/config.toml"); assert!(config.contains("git-fetch-with-cli = true")); assert!(config.contains("rustflags = [\"-Dwarnings\"]")); assert!(config.contains("frequency = \"always\"")); assert!(workspace_path(&["justfile"]).is_file(), "missing justfile"); assert!( workspace_path(&["bacon.toml"]).is_file(), "missing bacon.toml" ); let docs = read_workspace_text(&["docs", "jade-discipline.md"], "jade discipline docs"); let maintainer_notes = read_workspace_text(&["docs", "maintainer-notes.md"], "maintainer notes"); assert!(docs.contains("Jade Discipline")); assert!(docs.contains("cargo clippy --all-targets --all-features -- -D warnings -W clippy::pedantic -W clippy::nursery")); assert!(docs.contains("Miri, fuzzing, sanitizer, no-panic, and Loom checks are Jade gates")); assert!(docs.contains( "Missing tools, missing harnesses, or platform discomfort are failures by default" )); assert!(docs.contains("Global `allow` is reserved for two cases only")); assert!(docs.contains("smallest code-local scope")); assert!(docs.contains("Install")); assert!(docs.contains("just")); assert!(docs.contains("bacon")); assert!(maintainer_notes.contains("Jade has no optional safety tier")); assert!(maintainer_notes.contains("Every JSON-capable Mercury tool")); assert!(maintainer_notes.contains("is the shared AST/indexing engine")); } #[test] fn release_packaging_scripts_and_docs_exist() { for script_name in [ "package-toolbox.ps1", "install-package-toolbox.ps1", "uninstall-package-toolbox.ps1", "generate-ai-skill.ps1", "check-ai-skill.ps1", ] { assert!( script_path(script_name).is_file(), "missing packaging script {script_name}" ); } let readme = read_workspace_text(&["README.md"], "README.md"); assert!(readme.contains("just")); assert!(readme.contains("bacon")); assert!(readme.contains("## Portable Package")); assert!(readme.contains(r".\scripts\package-toolbox.ps1")); assert!(readme.contains("install-package-toolbox.ps1")); assert!(readme.contains("mercury-toolbox-package.json")); assert!(readme.contains("SHA256SUMS.txt")); assert!(readme.contains("generate-ai-skill.ps1")); assert!(readme.contains(r".\skills\mercury-toolbox\")); assert!(readme.contains("### `msudo`")); assert!(readme.contains("HIGH RISK")); assert!(readme.contains("top-level high-risk toolbox command")); assert!(readme.contains("msudo status --json")); assert!(readme.contains("Select-Object ok,host,supports_runas,is_elevated")); assert!(readme.contains("msudo --help")); assert!(readme.contains("msudo run --help")); } #[test] #[allow(clippy::too_many_lines)] fn powershell_gate_assets_and_docs_exist() { let root = workspace_root(); assert!( script_path("check-powershell.ps1").is_file(), "missing PowerShell gate script" ); assert!( script_path("cargo-flamegraph-windows.ps1").is_file(), "missing Windows flamegraph wrapper script" ); assert!( workspace_path(&["PSScriptAnalyzerSettings.psd1"]).is_file(), "missing PowerShell analyzer settings" ); let check_jade = read_workspace_text(&["scripts", "check-jade.ps1"], "scripts/check-jade.ps1"); assert!(check_jade.contains("check-powershell.ps1")); assert!(check_jade.contains("check-ai-skill.ps1")); assert!(check_jade.contains("check-jade-hardening.ps1")); assert!( check_jade.contains("Invoke-TimedNativeWithEnvironment"), "Jade coverage gate should be able to isolate cargo-llvm-cov environment" ); assert!( check_jade.contains("CARGO_INCREMENTAL") && check_jade.contains("RUSTC_WRAPPER"), "Jade coverage gate should disable incremental and rustc-wrapper for cargo-llvm-cov" ); assert!( check_jade.contains("CARGO_TARGET_DIR") && check_jade.contains("mercury-jade-llvm-cov") && check_jade.contains("cargo llvm-cov clean") && check_jade .contains("Invoke-TimedNativeWithEnvironment -Name 'cargo llvm-cov clean'"), "Jade coverage gate should use a per-run isolated cargo target dir for clean and nextest" ); assert!( check_jade.contains("MERCURY_JADE_COVERAGE_ROOT") && check_jade.contains("C:\\tmp") && check_jade.contains("'mtcov'") && check_jade.contains(".Substring(0, 8)"), "Jade coverage target dir should stay short enough for Windows llvm-cov object argv" ); assert!( check_jade.contains( "'llvm-cov',\n '--jobs',\n '1',\n 'nextest'" ), "Jade coverage gate should limit cargo-llvm-cov build jobs before the nextest subcommand" ); assert_justfile_test_recipes(&root); let ecosystem = read_workspace_text( &["scripts", "check-ecosystem.ps1"], "ecosystem check script", ); assert!( ecosystem.contains("toolbox:all-binaries-report-version") && ecosystem.contains("Test-ToolboxBinaryVersions"), "ecosystem gate should prove every toolbox binary reports --version" ); assert!( ecosystem.contains("toolbox:all-binaries-no-args-contract") && ecosystem.contains("Test-ToolboxNoArgsContracts"), "ecosystem gate should prove every toolbox binary has bounded no-args behavior" ); assert!( ecosystem.contains("toolbox:all-binaries-invalid-flag-contract") && ecosystem.contains("Test-ToolboxInvalidFlagContracts"), "ecosystem gate should prove every toolbox binary has bounded invalid-flag diagnostics" ); assert!( ecosystem.contains("toolbox:all-binaries-structured-output-help") && ecosystem.contains("Test-ToolboxStructuredOutputHelpContracts"), "ecosystem gate should prove every toolbox binary exposes structured output help" ); assert!( ecosystem.contains("toolbox:malformed-jsonl-stdin-contract") && ecosystem.contains("Test-ToolboxMalformedJsonlStdinContracts"), "ecosystem gate should prove malformed JSONL stdin is bounded for input-format commands" ); assert!( ecosystem.contains("toolbox:valid-jsonl-path-stream-smokes"), "ecosystem gate should prove representative positive JSONL path-stream behavior" ); assert!( ecosystem.contains("toolbox:functional-toon-smokes"), "ecosystem gate should prove representative functional TOON output smokes" ); let check_hardening = read_workspace_text( &["scripts", "check-jade-hardening.ps1"], "scripts/check-jade-hardening.ps1", ); for required_gate in [ "cargo miri setup", "NightlyToolchain", "'fuzz'", "'run'", "json_family_decode", "-Zsanitizer=address", "check-no-panic.ps1", "loom_capture", "Mode 'hardening'", "ValidateRange(1, 3600)", "Only = 'All'", ] { assert!( check_hardening.contains(required_gate), "hardening script should contain {required_gate:?}" ); } assert!(check_hardening.contains("exemption requires a non-empty reason")); let jade_install = read_workspace_text( &["scripts", "install-jade-tooling.ps1"], "scripts/install-jade-tooling.ps1", ); assert!(jade_install.contains("PSScriptAnalyzer")); assert!(jade_install.contains("cargo-binstall")); assert!(jade_install.contains("\"just\", \"bacon\"")); assert!(jade_install.contains("\"component\", \"add\", \"miri\"")); assert!(jade_install.contains("\"cargo-udeps\", \"cargo-llvm-cov\"")); assert!(jade_install.contains("\"install\", \"cargo-fuzz\"")); let docs = read_workspace_text(&["docs", "jade-discipline.md"], "jade discipline docs"); assert!(docs.contains("PowerShell Gate")); assert!(docs.contains("check-powershell.ps1")); assert!(docs.contains("check-ai-skill.ps1")); assert!(docs.contains("PSScriptAnalyzer")); assert!(docs.contains("cargo-flamegraph-windows.ps1")); let readme = read_workspace_text(&["README.md"], "README.md"); assert!(readme.contains("cargo-flamegraph-windows.ps1")); } fn assert_justfile_test_recipes(root: &std::path::Path) { let justfile = fs::read_to_string(root.join("justfile")).expect("justfile"); assert!( justfile.contains("coverage:\n cargo llvm-cov nextest --all-features --summary-only"), "just coverage should keep a fast local coverage path without forcing Jade's serial coverage gate" ); assert!( !justfile.contains("coverage:\n cargo llvm-cov clean --workspace"), "just coverage should not pre-clean coverage artifacts on every local iteration" ); assert!( justfile.contains("test:\n cargo nextest run --all-features"), "just test should keep the fast incremental nextest path for local iteration" ); assert!( justfile.contains("stable-test:") && justfile.contains( "CARGO_INCREMENTAL = '0'; cargo nextest run --all-features --run-ignored all", ), "stable-test should keep the non-incremental Windows cleanup-race path and slow integration coverage" ); } #[test] #[allow(clippy::too_many_lines)] fn repo_temp_paths_are_audited_and_use_exclusive_writes() { let root = workspace_root(); let production_temp_dir_hits = production_source_hits( &root, &[ "std::env::temp_dir()", "env::temp_dir()", "tempfile::", "NamedTempFile", "TempDir::new", "tempdir()", ], ); assert_eq!( production_temp_dir_hits, [ "crates\\argv\\src\\lib.rs:std::env::temp_dir().join(format!(", "crates\\envdiff\\src\\lib.rs:std::env::temp_dir().join(format!(", "crates\\msudo\\src\\lib.rs:let temp_dir = std::env::temp_dir();", "crates\\runtimekit\\src\\lib.rs:std::env::temp_dir().join(format!(\"{prefix}-{unique}.{extension}\"))", ], "production temp root use must stay explicitly audited" ); for (path, required) in [ ( "crates/runtimekit/src/lib.rs", &[ "fn write_shell_wrapper_file", ".create_new(true)", "refusing to replace existing shell wrapper", ][..], ), ( "crates/argv/src/lib.rs", &[ "fn write_cmd_wrapper_file", ".create_new(true)", "refusing to replace existing cmd inspect wrapper", ][..], ), ( "crates/envdiff/src/lib.rs", &[ "fn write_temp_file_exclusive", ".create_new(true)", "fn create_temp_dir_exclusive", "fs::create_dir(path)", ][..], ), ( "crates/msudo/src/lib.rs", &[ "fn write_relay_exit_status", ".create_new(true)", "failed to create relay exit status", ][..], ), ( "crates/runprobe/src/lib.rs", &[ "fn write_log_file_exclusive", ".create_new(true)", "refusing to replace existing runprobe log", ][..], ), ( "crates/windowsupport/src/sudo.rs", &[ "fn create_relay_output_file", ".create_new(true)", "FILE_FLAG_OPEN_REPARSE_POINT", ][..], ), ] { let body = fs::read_to_string(root.join(path)).unwrap_or_else(|error| { panic!("failed to read {path}: {error}"); }); for needle in required { assert!( body.contains(needle), "{path} should keep temp/log output guard {needle:?}" ); } } } fn production_source_hits(root: &std::path::Path, needles: &[&str]) -> Vec { let mut hits = Vec::new(); collect_production_source_hits(&root.join("crates"), root, needles, &mut hits); hits.sort(); hits } fn collect_production_source_hits( directory: &std::path::Path, root: &std::path::Path, needles: &[&str], hits: &mut Vec, ) { for entry in fs::read_dir(directory).unwrap_or_else(|error| { panic!("failed to read {}: {error}", directory.display()); }) { let path = entry.expect("directory entry").path(); if path.is_dir() { if path.file_name().and_then(|name| name.to_str()) != Some("tests") { collect_production_source_hits(&path, root, needles, hits); } continue; } if path.extension().and_then(|extension| extension.to_str()) != Some("rs") { continue; } collect_file_hits(&path, root, needles, hits); } } fn collect_file_hits( path: &std::path::Path, root: &std::path::Path, needles: &[&str], hits: &mut Vec, ) { let body = fs::read_to_string(path).unwrap_or_else(|error| { panic!("failed to read {}: {error}", path.display()); }); let mut in_test_region = path.components().any(|component| { component .as_os_str() .to_string_lossy() .eq_ignore_ascii_case("tests") }); for line in body.lines() { let trimmed = line.trim(); if trimmed == "#[cfg(test)]" || trimmed.starts_with("#[test]") { in_test_region = true; } if !in_test_region && needles.iter().any(|needle| trimmed.contains(needle)) { let relative = path.strip_prefix(root).unwrap_or(path); hits.push(format!("{}:{}", relative.display(), trimmed)); } } } #[test] fn deny_advisory_ignores_carry_review_evidence() { let deny = read_workspace_text(&["deny.toml"], "deny.toml"); let advisory = "RUSTSEC-2024-0436"; let offset = deny .find(advisory) .unwrap_or_else(|| panic!("deny.toml should mention {advisory}")); let context_start = deny[..offset] .rfind("[advisories]") .expect("advisories section"); let context = &deny[context_start..offset]; for required in [ "Package:", "Reachability:", "Reviewed:", "Upgrade/follow-up:", ] { assert!( context.contains(required), "advisory ignore {advisory} should document {required}" ); } } #[test] fn ai_asset_checks_self_heal_generated_drift_before_failing() { for script_name in ["check-ai-prompt.ps1", "check-ai-skill.ps1"] { let script = read_workspace_text(&["scripts", script_name], script_name); assert!( script.contains("Invoke-GeneratorCheck"), "{script_name} should use the shared check/regenerate/recheck helper" ); assert!( script.contains("Invoke-GeneratorWrite"), "{script_name} should regenerate stale generated assets automatically" ); assert!( script.contains("still out of date after regeneration"), "{script_name} should only ask for manual intervention after regeneration fails" ); } let docs = read_workspace_text(&["docs", "jade-discipline.md"], "jade docs"); assert!( docs.contains("self-heal generated asset drift"), "Jade docs should describe the AI asset gate's self-healing behavior" ); }