mod common;
use common::{rsigma, temp_file};
use predicates::prelude::*;
const MIXED_CORPUS: &str = concat!(
r#"{"vendor":"acme","event_type":"alert","severity":5}"#,
"\n",
r#"{"vendor":"acme","event_type":"alert","severity":3}"#,
"\n",
r#"{"vendor":"acme","event_type":"alert","severity":8}"#,
"\n",
r#"{"vendor":"acme","event_type":"alert","severity":2}"#,
"\n",
r#"{"ecs.version":"8.11.0","process":{"command_line":"whoami"}}"#,
"\n",
);
#[test]
fn discovers_candidate_from_ndjson_stdin() {
rsigma()
.args(["engine", "discover-schemas", "--output-format", "json"])
.write_stdin(MIXED_CORPUS)
.assert()
.success()
.stdout(predicate::str::contains("\"events_mined\": 4"))
.stdout(predicate::str::contains("\"discovered_alert\""))
.stdout(predicate::str::contains("\"signatures_yaml\""));
}
#[test]
fn emit_yaml_prints_only_the_schemas_block() {
let out = rsigma()
.args(["engine", "discover-schemas", "--emit", "yaml"])
.write_stdin(MIXED_CORPUS)
.output()
.expect("run discover");
assert!(out.status.success());
let yaml = String::from_utf8(out.stdout).expect("utf8");
assert!(yaml.trim_start().starts_with("schemas:"), "got: {yaml}");
assert!(yaml.contains("event_type"));
assert!(!yaml.contains("SUPPORT"));
assert!(!yaml.contains("Paste into"));
}
#[test]
fn dry_run_reports_before_and_after_counts() {
rsigma()
.args([
"engine",
"discover-schemas",
"--dry-run",
"--output-format",
"table",
])
.write_stdin(MIXED_CORPUS)
.assert()
.success()
.stdout(predicate::str::contains("Dry run (classification impact)"))
.stdout(predicate::str::contains("generic_json: 4 -> 0"));
}
#[test]
fn emitted_yaml_round_trips_through_classify() {
let out = rsigma()
.args(["engine", "discover-schemas", "--emit", "yaml"])
.write_stdin(MIXED_CORPUS)
.output()
.expect("run discover");
assert!(out.status.success());
let yaml = String::from_utf8(out.stdout).expect("utf8");
let config = temp_file(".yml", &yaml);
rsigma()
.args([
"engine",
"classify",
"-e",
r#"{"vendor":"acme","event_type":"alert","severity":9}"#,
"--schema-config",
config.path().to_str().unwrap(),
"--output-format",
"json",
])
.assert()
.success()
.stdout(predicate::str::contains("\"schema\": \"discovered_alert\""));
}
#[test]
fn no_value_markers_yields_presence_predicates() {
let out = rsigma()
.args([
"engine",
"discover-schemas",
"--emit",
"yaml",
"--no-value-markers",
])
.write_stdin(MIXED_CORPUS)
.output()
.expect("run discover");
assert!(out.status.success());
let yaml = String::from_utf8(out.stdout).expect("utf8");
assert!(yaml.contains("field_present:"), "got: {yaml}");
assert!(
!yaml.contains("equals:"),
"value markers should be off: {yaml}"
);
}
#[test]
fn evtx_path_is_rejected() {
rsigma()
.args(["engine", "discover-schemas", "-e", "@evidence.evtx"])
.assert()
.failure()
.stderr(predicate::str::contains(".evtx"));
}