feat(api): onboarding endpoints for unified targets (#142)
This commit was merged in pull request #142.
This commit is contained in:
@@ -25,8 +25,9 @@ impl TestServer {
|
||||
let mongodb_uri = std::env::var("TEST_MONGODB_URI")
|
||||
.unwrap_or_else(|_| "mongodb://root:example@localhost:27017/?authSource=admin".into());
|
||||
|
||||
// Unique database name per test run to avoid collisions
|
||||
let db_name = format!("test_{}", uuid::Uuid::new_v4().simple());
|
||||
// Unique db-name prefix per run. Must fit the pool's 30-char cap
|
||||
// (`<prefix>_<32 hex>` <= 63), so use a 16-hex-char suffix.
|
||||
let db_name = format!("t_{}", &uuid::Uuid::new_v4().simple().to_string()[..16]);
|
||||
|
||||
let db_pool = DatabasePool::connect(&mongodb_uri, &db_name)
|
||||
.await
|
||||
|
||||
@@ -2,5 +2,6 @@ mod cascade_delete;
|
||||
mod dast;
|
||||
mod findings;
|
||||
mod health;
|
||||
mod onboarding;
|
||||
mod repositories;
|
||||
mod stats;
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user