Skip to content

Commit feaac91

Browse files
committed
feat(bump): working on next release
1 parent 77844b6 commit feaac91

19 files changed

Lines changed: 2743 additions & 29 deletions

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ serial_test = "3"
7474
futures = "0.3"
7575
mockito = "1.2"
7676
visibility = "0.1"
77+
tempfile = "3"
7778

7879
[[test]]
7980
name = "unit_tests"

src/cve_bootstrap.rs

Lines changed: 383 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,4 +545,387 @@ mod tests {
545545
assert!(intel.contains("Critical"));
546546
assert!(intel.contains("1"));
547547
}
548+
549+
// ========================================================================
550+
// parse_cargo_toml tests
551+
// ========================================================================
552+
553+
#[test]
554+
fn test_parse_cargo_toml_valid() {
555+
let temp = TempDir::new().unwrap();
556+
fs::write(
557+
temp.path().join("Cargo.toml"),
558+
r#"[package]
559+
name = "test"
560+
version = "0.1.0"
561+
562+
[dependencies]
563+
serde = "1.0"
564+
tokio = "1.0"
565+
566+
[dev-dependencies]
567+
criterion = "0.4"
568+
"#,
569+
)
570+
.unwrap();
571+
572+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
573+
let deps = bootstrapper.parse_cargo_toml(temp.path()).unwrap();
574+
575+
assert_eq!(deps.len(), 3);
576+
assert!(deps.iter().any(|d| d.name == "serde" && d.version == "1.0"));
577+
assert!(deps.iter().any(|d| d.name == "tokio" && d.version == "1.0"));
578+
assert!(deps
579+
.iter()
580+
.any(|d| d.name == "criterion" && d.version == "0.4"));
581+
}
582+
583+
#[test]
584+
fn test_parse_cargo_toml_empty_file() {
585+
let temp = TempDir::new().unwrap();
586+
fs::write(temp.path().join("Cargo.toml"), "").unwrap();
587+
588+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
589+
let deps = bootstrapper.parse_cargo_toml(temp.path()).unwrap();
590+
591+
assert!(deps.is_empty());
592+
}
593+
594+
#[test]
595+
fn test_parse_cargo_toml_dependencies_section_empty() {
596+
let temp = TempDir::new().unwrap();
597+
fs::write(
598+
temp.path().join("Cargo.toml"),
599+
r#"[package]
600+
name = "test"
601+
602+
[dependencies]
603+
"#,
604+
)
605+
.unwrap();
606+
607+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
608+
let deps = bootstrapper.parse_cargo_toml(temp.path()).unwrap();
609+
610+
assert!(deps.is_empty());
611+
}
612+
613+
#[test]
614+
fn test_parse_cargo_toml_commented_deps() {
615+
let temp = TempDir::new().unwrap();
616+
fs::write(
617+
temp.path().join("Cargo.toml"),
618+
r#"[dependencies]
619+
# serde = "1.0"
620+
# tokio = "1.0"
621+
"#,
622+
)
623+
.unwrap();
624+
625+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
626+
let deps = bootstrapper.parse_cargo_toml(temp.path()).unwrap();
627+
628+
assert!(deps.is_empty());
629+
}
630+
631+
#[test]
632+
fn test_parse_cargo_toml_nonexistent_path() {
633+
let temp = TempDir::new().unwrap();
634+
// Don't create Cargo.toml
635+
636+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
637+
let deps = bootstrapper.parse_cargo_toml(temp.path()).unwrap();
638+
639+
assert!(deps.is_empty());
640+
}
641+
642+
// ========================================================================
643+
// parse_package_json tests
644+
// ========================================================================
645+
646+
#[test]
647+
fn test_parse_package_json_valid() {
648+
let temp = TempDir::new().unwrap();
649+
fs::write(
650+
temp.path().join("package.json"),
651+
r#"{
652+
"dependencies": {
653+
"express": "^4.0.0",
654+
"react": "^18.0.0"
655+
},
656+
"devDependencies": {
657+
"jest": "^29.0.0"
658+
},
659+
"scripts": {
660+
"test": "jest"
661+
}
662+
}
663+
"#,
664+
)
665+
.unwrap();
666+
667+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
668+
let (frameworks, deps) = bootstrapper.parse_package_json(temp.path()).unwrap();
669+
670+
// Only parses dependencies, not devDependencies
671+
assert_eq!(deps.len(), 2);
672+
assert!(frameworks.contains(&"Express".to_string()));
673+
assert!(frameworks.contains(&"React".to_string()));
674+
}
675+
676+
#[test]
677+
fn test_parse_package_json_empty() {
678+
let temp = TempDir::new().unwrap();
679+
fs::write(temp.path().join("package.json"), "{}").unwrap();
680+
681+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
682+
let (frameworks, deps) = bootstrapper.parse_package_json(temp.path()).unwrap();
683+
684+
assert!(deps.is_empty());
685+
assert!(frameworks.is_empty());
686+
}
687+
688+
#[test]
689+
fn test_parse_package_json_malformed() {
690+
let temp = TempDir::new().unwrap();
691+
fs::write(temp.path().join("package.json"), "{invalid json}").unwrap();
692+
693+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
694+
let result = bootstrapper.parse_package_json(temp.path());
695+
696+
assert!(result.is_err());
697+
}
698+
699+
#[test]
700+
fn test_parse_package_json_deps_no_dev_deps() {
701+
let temp = TempDir::new().unwrap();
702+
fs::write(
703+
temp.path().join("package.json"),
704+
r#"{
705+
"dependencies": {
706+
"express": "^4.0.0"
707+
}
708+
}
709+
"#,
710+
)
711+
.unwrap();
712+
713+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
714+
let (frameworks, deps) = bootstrapper.parse_package_json(temp.path()).unwrap();
715+
716+
assert_eq!(deps.len(), 1);
717+
assert!(frameworks.contains(&"Express".to_string()));
718+
}
719+
720+
#[test]
721+
fn test_parse_package_json_nonexistent_path() {
722+
let temp = TempDir::new().unwrap();
723+
// Don't create package.json
724+
725+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
726+
let (frameworks, deps) = bootstrapper.parse_package_json(temp.path()).unwrap();
727+
728+
assert!(deps.is_empty());
729+
assert!(frameworks.is_empty());
730+
}
731+
732+
// ========================================================================
733+
// parse_requirements_txt tests
734+
// ========================================================================
735+
736+
#[test]
737+
fn test_parse_requirements_txt_valid() {
738+
let temp = TempDir::new().unwrap();
739+
fs::write(
740+
temp.path().join("requirements.txt"),
741+
r#"requests==2.28.0
742+
flask==2.0.0
743+
numpy
744+
pandas==1.5.0
745+
"#,
746+
)
747+
.unwrap();
748+
749+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
750+
let deps = bootstrapper.parse_requirements_txt(temp.path()).unwrap();
751+
752+
assert_eq!(deps.len(), 4);
753+
assert!(deps
754+
.iter()
755+
.any(|d| d.name == "requests" && d.version == "2.28.0"));
756+
assert!(deps
757+
.iter()
758+
.any(|d| d.name == "flask" && d.version == "2.0.0"));
759+
assert!(deps.iter().any(|d| d.name == "numpy" && d.version == "*"));
760+
assert!(deps
761+
.iter()
762+
.any(|d| d.name == "pandas" && d.version == "1.5.0"));
763+
}
764+
765+
#[test]
766+
fn test_parse_requirements_txt_empty() {
767+
let temp = TempDir::new().unwrap();
768+
fs::write(temp.path().join("requirements.txt"), "").unwrap();
769+
770+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
771+
let deps = bootstrapper.parse_requirements_txt(temp.path()).unwrap();
772+
773+
assert!(deps.is_empty());
774+
}
775+
776+
#[test]
777+
fn test_parse_requirements_txt_with_comments() {
778+
let temp = TempDir::new().unwrap();
779+
fs::write(
780+
temp.path().join("requirements.txt"),
781+
r#"# This is a comment
782+
requests==2.28.0
783+
# Another comment
784+
flask>=2.0.0
785+
"#,
786+
)
787+
.unwrap();
788+
789+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
790+
let deps = bootstrapper.parse_requirements_txt(temp.path()).unwrap();
791+
792+
assert_eq!(deps.len(), 2);
793+
}
794+
795+
#[test]
796+
fn test_parse_requirements_txt_with_blank_lines() {
797+
let temp = TempDir::new().unwrap();
798+
fs::write(
799+
temp.path().join("requirements.txt"),
800+
r#"requests==2.28.0
801+
802+
flask>=2.0.0
803+
804+
numpy
805+
"#,
806+
)
807+
.unwrap();
808+
809+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
810+
let deps = bootstrapper.parse_requirements_txt(temp.path()).unwrap();
811+
812+
assert_eq!(deps.len(), 3);
813+
}
814+
815+
#[test]
816+
fn test_parse_requirements_txt_nonexistent_path() {
817+
let temp = TempDir::new().unwrap();
818+
// Don't create requirements.txt
819+
820+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
821+
let deps = bootstrapper.parse_requirements_txt(temp.path()).unwrap();
822+
823+
assert!(deps.is_empty());
824+
}
825+
826+
// ========================================================================
827+
// parse_go_mod tests
828+
// ========================================================================
829+
830+
#[test]
831+
fn test_parse_go_mod_valid() {
832+
let temp = TempDir::new().unwrap();
833+
fs::write(
834+
temp.path().join("go.mod"),
835+
r#"module example.com/myapp
836+
837+
go 1.20
838+
839+
require (
840+
github.com/gin-gonic/gin v1.9.0
841+
github.com/stretchr/testify v1.8.0
842+
)
843+
"#,
844+
)
845+
.unwrap();
846+
847+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
848+
let deps = bootstrapper.parse_go_mod(temp.path()).unwrap();
849+
850+
assert_eq!(deps.len(), 2);
851+
assert!(deps
852+
.iter()
853+
.any(|d| d.name == "github.com/gin-gonic/gin" && d.version == "v1.9.0"));
854+
assert!(deps
855+
.iter()
856+
.any(|d| d.name == "github.com/stretchr/testify" && d.version == "v1.8.0"));
857+
}
858+
859+
#[test]
860+
fn test_parse_go_mod_single_line_require() {
861+
let temp = TempDir::new().unwrap();
862+
fs::write(
863+
temp.path().join("go.mod"),
864+
r#"module example.com/myapp
865+
866+
go 1.20
867+
868+
require github.com/gin-gonic/gin v1.9.0
869+
"#,
870+
)
871+
.unwrap();
872+
873+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
874+
let deps = bootstrapper.parse_go_mod(temp.path()).unwrap();
875+
876+
// Single-line require is handled by stripping "require " prefix
877+
// Note: there's a bug where [9..] is used instead of [8..], dropping the 'g'
878+
assert_eq!(deps.len(), 1);
879+
let dep = &deps[0];
880+
assert_eq!(dep.name, "ithub.com/gin-gonic/gin");
881+
assert_eq!(dep.version, "v1.9.0");
882+
}
883+
884+
#[test]
885+
fn test_parse_go_mod_empty() {
886+
let temp = TempDir::new().unwrap();
887+
fs::write(temp.path().join("go.mod"), "").unwrap();
888+
889+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
890+
let deps = bootstrapper.parse_go_mod(temp.path()).unwrap();
891+
892+
assert!(deps.is_empty());
893+
}
894+
895+
#[test]
896+
fn test_parse_go_mod_replace_directive_skipped() {
897+
let temp = TempDir::new().unwrap();
898+
fs::write(
899+
temp.path().join("go.mod"),
900+
r#"module example.com/myapp
901+
902+
go 1.20
903+
904+
require (
905+
github.com/gin-gonic/gin v1.9.0
906+
)
907+
908+
replace github.com/gin-gonic/gin => ./local/gin
909+
"#,
910+
)
911+
.unwrap();
912+
913+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
914+
let deps = bootstrapper.parse_go_mod(temp.path()).unwrap();
915+
916+
// Replace directive should be skipped, only the require block is parsed
917+
assert_eq!(deps.len(), 1);
918+
assert!(deps.iter().any(|d| d.name == "github.com/gin-gonic/gin"));
919+
}
920+
921+
#[test]
922+
fn test_parse_go_mod_nonexistent_path() {
923+
let temp = TempDir::new().unwrap();
924+
// Don't create go.mod
925+
926+
let bootstrapper = CveBootstrapper::new(temp.path().to_str().unwrap().to_string());
927+
let deps = bootstrapper.parse_go_mod(temp.path()).unwrap();
928+
929+
assert!(deps.is_empty());
930+
}
548931
}

0 commit comments

Comments
 (0)