use crate::common::TestServer; use serde_json::json; #[tokio::test] async fn create_list_and_applicable_scans() { let server = TestServer::start().await; // Initially empty. let resp = server.get("/api/v1/targets").await; assert_eq!(resp.status(), 200); let body: serde_json::Value = resp.json().await.unwrap(); assert_eq!(body["data"].as_array().unwrap().len(), 0); // Create a web-app target with a git repo + a live URL. let resp = server .post( "/api/v1/targets", &json!({ "name": "acme-web", "target_type": "web_app", "artifacts": [ { "kind": "git_repo", "source_ref": "https://git/acme.git", "branch": "main" }, { "kind": "live_url", "source_ref": "https://acme.example.com" } ] }), ) .await; assert_eq!(resp.status(), 200); let body: serde_json::Value = resp.json().await.unwrap(); let id = body["data"]["_id"]["$oid"].as_str().unwrap().to_string(); assert!(!id.is_empty()); assert_eq!(body["data"]["artifacts"].as_array().unwrap().len(), 2); // List returns it. let resp = server.get("/api/v1/targets").await; let body: serde_json::Value = resp.json().await.unwrap(); assert_eq!(body["data"].as_array().unwrap().len(), 1); // Applicable scans: SAST present + DAST offered (live URL present), pentest supported. let resp = server .get(&format!("/api/v1/targets/{id}/applicable-scans")) .await; assert_eq!(resp.status(), 200); let body: serde_json::Value = resp.json().await.unwrap(); let scans = body["data"]["scans"].as_array().unwrap(); let names: Vec<&str> = scans.iter().filter_map(|s| s["scan"].as_str()).collect(); assert!(names.contains(&"sast")); assert!(names.contains(&"dast")); assert_eq!(body["data"]["pentest_supported"], true); server.cleanup().await; } #[tokio::test] async fn detect_classifies_a_plc_target() { let server = TestServer::start().await; // A PLC project artifact is a strong kind-based signal. let resp = server .post( "/api/v1/targets", &json!({ "name": "line-controller", "target_type": "backend_service", // deliberately wrong; detect should suggest PLC "artifacts": [ { "kind": "plc_project", "source_ref": "line.xml", "plc_format": "plcopen_xml" } ] }), ) .await; let body: serde_json::Value = resp.json().await.unwrap(); let id = body["data"]["_id"]["$oid"].as_str().unwrap().to_string(); let resp = server .post(&format!("/api/v1/targets/{id}/detect"), &json!({})) .await; assert_eq!(resp.status(), 200); let body: serde_json::Value = resp.json().await.unwrap(); assert_eq!(body["data"]["classification"]["suggested"], "plc_sps"); server.cleanup().await; } #[tokio::test] async fn add_artifact_and_delete_target() { let server = TestServer::start().await; let resp = server .post( "/api/v1/targets", &json!({ "name": "svc", "target_type": "backend_service" }), ) .await; let body: serde_json::Value = resp.json().await.unwrap(); let id = body["data"]["_id"]["$oid"].as_str().unwrap().to_string(); // Attach a git repo. let resp = server .post( &format!("/api/v1/targets/{id}/artifacts"), &json!({ "kind": "git_repo", "source_ref": "https://git/svc.git" }), ) .await; assert_eq!(resp.status(), 200); let body: serde_json::Value = resp.json().await.unwrap(); assert_eq!(body["data"]["artifacts"].as_array().unwrap().len(), 1); // Delete it. let resp = server.delete(&format!("/api/v1/targets/{id}")).await; assert_eq!(resp.status(), 200); let resp = server.get(&format!("/api/v1/targets/{id}")).await; assert_eq!(resp.status(), 404); server.cleanup().await; }