mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-15 20:05:13 +02:00
[pitboss/grind] deferred session-0023 (20260516T052512Z-20f8)
This commit is contained in:
parent
1d1975a2ea
commit
6189c4a4c5
20 changed files with 297 additions and 1 deletions
|
|
@ -76,6 +76,7 @@ fn verdict(status: VerifyStatus, reason: Option<InconclusiveReason>) -> VerifyRe
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -584,6 +584,7 @@ pub fn run_shape_fixture_lang(
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
}
|
||||
}
|
||||
Err(RunError::NoPayloadsForCap) => VerifyResult {
|
||||
|
|
@ -598,6 +599,7 @@ pub fn run_shape_fixture_lang(
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
},
|
||||
Err(e) => VerifyResult {
|
||||
finding_id: spec.finding_id.clone(),
|
||||
|
|
@ -611,6 +613,7 @@ pub fn run_shape_fixture_lang(
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ fn diag_with_verdict(status: VerifyStatus) -> Diag {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
},
|
||||
VerifyStatus::NotConfirmed => VerifyResult {
|
||||
finding_id: "abc123".into(),
|
||||
|
|
@ -93,6 +94,7 @@ fn diag_with_verdict(status: VerifyStatus) -> Diag {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
},
|
||||
VerifyStatus::Unsupported => VerifyResult {
|
||||
finding_id: "abc123".into(),
|
||||
|
|
@ -106,6 +108,7 @@ fn diag_with_verdict(status: VerifyStatus) -> Diag {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
},
|
||||
VerifyStatus::Inconclusive => VerifyResult {
|
||||
finding_id: "abc123".into(),
|
||||
|
|
@ -119,6 +122,7 @@ fn diag_with_verdict(status: VerifyStatus) -> Diag {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ fn set_verdict(
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -170,6 +171,7 @@ fn new_confirmed_fails_no_new_confirmed_gate() {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ mod go_fixture_tests {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ mod java_fixture_tests {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ mod js_fixture_tests {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ fn json_dynamic_verdict_confirmed_serialises_correctly() {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
}),
|
||||
..Default::default()
|
||||
});
|
||||
|
|
@ -100,6 +101,7 @@ fn json_dynamic_verdict_not_confirmed_serialises_correctly() {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
}),
|
||||
..Default::default()
|
||||
});
|
||||
|
|
@ -165,6 +167,7 @@ fn json_unsupported_verdict_has_reason() {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
}),
|
||||
..Default::default()
|
||||
});
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ mod php_fixture_tests {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ mod repro_determinism_tests {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ mod repro_hermetic_tests {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -350,6 +350,111 @@ except Exception as exc:
|
|||
"refuse_filesystem_confirm should be false when sandbox-exec is reachable"
|
||||
);
|
||||
}
|
||||
|
||||
/// Phase 18 verifier-side projection: when a real strict run lands a
|
||||
/// macOS `HardeningRecord`, `summarize_hardening` collapses it into
|
||||
/// the portable [`crate::evidence::HardeningSummary`] that
|
||||
/// `build_verdict` stamps on a `Confirmed` `VerifyResult`. Drives
|
||||
/// the same `sandbox::run` path the existing
|
||||
/// `path_traversal_payload_blocked_under_strict` test uses, then
|
||||
/// asserts on the projection that would land on
|
||||
/// `VerifyResult::hardening_outcome` if this run had triggered the
|
||||
/// finding's oracle.
|
||||
#[test]
|
||||
fn summarize_hardening_lands_path_traversal_on_strict_file_io_run() {
|
||||
unsafe { std::env::remove_var(SANDBOX_EXEC_BIN_ENV) };
|
||||
if !sandbox_exec_available() {
|
||||
eprintln!("SKIP: /usr/bin/sandbox-exec missing — cannot exercise wrap");
|
||||
return;
|
||||
}
|
||||
const FILE_IO: u32 = 1 << 5;
|
||||
let tmp = workdir();
|
||||
let harness = build_harness(tmp.path());
|
||||
let opts = strict_opts(FILE_IO);
|
||||
let result = sandbox::run(&harness, b"", &opts).expect("sandbox::run");
|
||||
let summary = nyx_scanner::dynamic::verify::summarize_hardening(&result)
|
||||
.expect("hardening summary should populate after a strict macOS run");
|
||||
assert_eq!(summary.backend, "macos-process");
|
||||
assert_eq!(summary.level, "sandboxed");
|
||||
assert_eq!(
|
||||
summary.profile, "path_traversal",
|
||||
"FILE_IO-cap strict run should select the path_traversal profile"
|
||||
);
|
||||
assert!(
|
||||
summary.primitives.is_empty(),
|
||||
"macOS backend records no per-primitive entries"
|
||||
);
|
||||
}
|
||||
|
||||
/// Standard-profile runs leave `SandboxOutcome::hardening_outcome`
|
||||
/// unset, so `summarize_hardening` returns `None` and
|
||||
/// `VerifyResult::hardening_outcome` stays `None`. Companion to
|
||||
/// `standard_profile_does_not_wrap_with_sandbox_exec`.
|
||||
#[test]
|
||||
fn summarize_hardening_returns_none_for_standard_profile_run() {
|
||||
unsafe { std::env::remove_var(SANDBOX_EXEC_BIN_ENV) };
|
||||
let tmp = workdir();
|
||||
let harness = build_harness(tmp.path());
|
||||
let opts = standard_opts();
|
||||
let result = sandbox::run(&harness, b"", &opts).expect("sandbox::run");
|
||||
assert!(
|
||||
nyx_scanner::dynamic::verify::summarize_hardening(&result).is_none(),
|
||||
"standard profile should leave hardening_outcome unset"
|
||||
);
|
||||
}
|
||||
|
||||
/// Round-trip the portable summary through JSON to lock in the
|
||||
/// repro-bundle wire shape: `VerifyResult::hardening_outcome` lands
|
||||
/// on `expected/verdict.json` so the eval-corpus tabulator and any
|
||||
/// downstream replay reads the same fields back.
|
||||
#[test]
|
||||
fn hardening_summary_round_trips_through_json() {
|
||||
use nyx_scanner::evidence::{HardeningSummary, HardeningPrimitive};
|
||||
let summary = HardeningSummary {
|
||||
backend: "macos-process".into(),
|
||||
level: "sandboxed".into(),
|
||||
profile: "path_traversal".into(),
|
||||
primitives: vec![],
|
||||
};
|
||||
let json = serde_json::to_string(&summary).expect("serialize");
|
||||
let parsed: HardeningSummary = serde_json::from_str(&json).expect("deserialize");
|
||||
assert_eq!(parsed, summary);
|
||||
|
||||
// Defaults: missing `profile` and `primitives` must decode as
|
||||
// empty so older `verdict.json` payloads keep round-tripping.
|
||||
let minimal: HardeningSummary =
|
||||
serde_json::from_str(r#"{"backend":"linux-process","level":"full"}"#)
|
||||
.expect("minimal decode");
|
||||
assert_eq!(minimal.profile, "");
|
||||
assert!(minimal.primitives.is_empty());
|
||||
|
||||
// Linux-shape: per-primitive entries decode + re-encode with
|
||||
// their `errno` field intact when populated.
|
||||
let with_primitives = HardeningSummary {
|
||||
backend: "linux-process".into(),
|
||||
level: "partial".into(),
|
||||
profile: "strict".into(),
|
||||
primitives: vec![
|
||||
HardeningPrimitive {
|
||||
name: "no_new_privs".into(),
|
||||
status: "applied".into(),
|
||||
errno: None,
|
||||
},
|
||||
HardeningPrimitive {
|
||||
name: "seccomp".into(),
|
||||
status: "failed".into(),
|
||||
errno: Some(1),
|
||||
},
|
||||
],
|
||||
};
|
||||
let json = serde_json::to_string(&with_primitives).expect("serialize primitives");
|
||||
assert!(
|
||||
json.contains("\"errno\":1"),
|
||||
"errno field should survive JSON round-trip; got: {json}"
|
||||
);
|
||||
let parsed: HardeningSummary = serde_json::from_str(&json).expect("decode primitives");
|
||||
assert_eq!(parsed, with_primitives);
|
||||
}
|
||||
}
|
||||
|
||||
// Non-macOS placeholder so `cargo nextest run --test sandbox_hardening_macos`
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ fn sarif_confirmed_verdict_sets_partial_fingerprint() {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
};
|
||||
|
||||
let result = sarif_result(diag_with_verdict(verdict));
|
||||
|
|
@ -111,6 +112,7 @@ fn sarif_not_confirmed_verdict_sets_partial_fingerprint() {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
};
|
||||
|
||||
let result = sarif_result(diag_with_verdict(verdict));
|
||||
|
|
@ -140,6 +142,7 @@ fn sarif_unsupported_verdict_sets_partial_fingerprint() {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
};
|
||||
|
||||
let result = sarif_result(diag_with_verdict(verdict));
|
||||
|
|
@ -174,6 +177,7 @@ fn sarif_inconclusive_verdict_sets_partial_fingerprint() {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
};
|
||||
|
||||
let result = sarif_result(diag_with_verdict(verdict));
|
||||
|
|
@ -224,6 +228,7 @@ fn sarif_confirmed_verdict_nyx_dynamic_verdict_contains_triggered_payload() {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
};
|
||||
|
||||
let result = sarif_result(diag_with_verdict(verdict));
|
||||
|
|
@ -257,6 +262,7 @@ fn sarif_all_four_statuses_produce_partial_fingerprint() {
|
|||
differential: None,
|
||||
replay_stable: None,
|
||||
wrong: None,
|
||||
hardening_outcome: None,
|
||||
};
|
||||
|
||||
let result = sarif_result(diag_with_verdict(verdict));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue