use super::args::{self, ScanOptions};
use super::{JOB_STATUSES, LIST_JOB_TYPES, MAX_PAGE, MAX_STREAM, SEVERITIES};
use scm::validation::{Mode, parse};
use serde_json::{Value, json};
const TARGET: &str = "00000000-0000-4000-8000-000000000201";
const JOBS: &str = "vendor:red-team-dp:0.93.0:list_jobs_v1_scan_get:query";
const ATTACKS: &str =
"vendor:red-team-dp:0.93.0:list_attacks_v1_report_static__job_id__list_attacks_get:query";
const CUSTOM_ATTACKS: &str = "vendor:red-team-dp:0.93.0:list_custom_attacks_v1_custom_attacks_job__job_id__list_custom_attacks_get:query";
const ERROR_LOGS: &str = "vendor:red-team-dp:0.93.0:list_error_logs_for_target_profile_v1_error_log_target_profile__target_id__get:query";
const SCAN_BODY: &str = "vendor:red-team-dp:0.93.0:create_job_v1_scan_post:body";
fn accepted(schema: &str, value: Value) -> bool {
parse(schema, value, Mode::Request).is_ok()
}
#[test]
fn list_queries_accept_exactly_the_cli_vocabularies() {
for status in JOB_STATUSES {
assert!(accepted(JOBS, json!({"status": status})), "{status}");
}
for job_type in LIST_JOB_TYPES {
assert!(accepted(JOBS, json!({"job_type": job_type})), "{job_type}");
}
assert!(accepted(
JOBS,
json!({"skip": 0, "limit": MAX_PAGE, "status": "COMPLETED", "job_type": "STATIC", "target_id": TARGET})
));
assert!(accepted(JOBS, json!({"limit": 1})));
for refused in [
json!({"limit": MAX_PAGE + 1}),
json!({"status": "completed"}),
json!({"status": "PROFILING"}),
json!({"status": ""}),
json!({"job_type": "static"}),
json!({"job_type": ""}),
json!({"target_id": "t-1"}),
json!({"target_id": ""}),
] {
assert!(!accepted(JOBS, refused.clone()), "{refused}");
}
}
#[test]
fn attack_queries_accept_the_cli_bound_and_severities() {
for severity in SEVERITIES {
assert!(
accepted(ATTACKS, json!({"limit": 20, "severity": severity})),
"{severity}"
);
}
assert!(accepted(ATTACKS, json!({"limit": MAX_PAGE})));
for refused in [
json!({"limit": MAX_PAGE + 1}),
json!({"severity": ""}),
json!({"severity": "high"}),
] {
assert!(!accepted(ATTACKS, refused.clone()), "{refused}");
}
assert!(accepted(CUSTOM_ATTACKS, json!({"limit": MAX_PAGE})));
assert!(accepted(CUSTOM_ATTACKS, json!({"limit": 1_000})));
assert!(!accepted(CUSTOM_ATTACKS, json!({"limit": 1_001})));
}
#[test]
fn error_log_queries_take_only_a_bounded_limit() {
assert!(accepted(ERROR_LOGS, json!({})));
assert!(accepted(ERROR_LOGS, json!({"limit": 1})));
assert!(accepted(ERROR_LOGS, json!({"limit": MAX_PAGE})));
for refused in [
json!({"limit": MAX_PAGE + 1}),
json!({"skip": 0}),
json!({"search": "upstream"}),
] {
assert!(!accepted(ERROR_LOGS, refused.clone()), "{refused}");
}
}
fn body(options: &ScanOptions<'_>) -> Value {
let spec = args::scan(options).unwrap();
let categories = json!({"SECURITY": ["JAILBREAK"]});
args::scan_body(&spec, Some(&categories), &["leak".to_owned()])
}
#[test]
fn scan_bodies_the_cli_accepts_pass_the_vendor_body() {
let base = ScanOptions {
target: TARGET,
name: "abc",
..ScanOptions::default()
};
let depth = MAX_STREAM.to_string();
let long = "x".repeat(255);
for options in [
base.clone(),
ScanOptions {
name: "\u{1F600}\u{1F600}\u{1F600}",
..base.clone()
},
ScanOptions {
name: &long,
..base.clone()
},
ScanOptions {
job_type: Some("DYNAMIC"),
depth: Some(&depth),
breadth: Some(&depth),
..base.clone()
},
ScanOptions {
job_type: Some("DYNAMIC"),
depth: Some("1"),
breadth: Some("1"),
..base.clone()
},
ScanOptions {
job_type: Some("CUSTOM"),
prompt_sets: Some("00000000-0000-4000-8000-000000000301"),
..base.clone()
},
] {
let body = body(&options);
assert!(accepted(SCAN_BODY, body.clone()), "{body}");
}
let mut deep = body(&ScanOptions {
job_type: Some("DYNAMIC"),
..base.clone()
});
deep["job_metadata"]["stream_depth"] = json!(MAX_STREAM + 1);
assert!(!accepted(SCAN_BODY, deep));
let mut wide = body(&ScanOptions {
job_type: Some("DYNAMIC"),
..base.clone()
});
wide["job_metadata"]["stream_breadth"] = json!(MAX_STREAM + 1);
assert!(!accepted(SCAN_BODY, wide));
let mut short = body(&base);
short["name"] = json!("\u{1F600}a");
assert!(!accepted(SCAN_BODY, short));
let mut opaque = body(&base);
opaque["target"]["uuid"] = json!("t-1");
assert!(!accepted(SCAN_BODY, opaque));
}