fix(prover-cli): harden cancellation and invalid input

Signed-off-by: Johnny Greco <jogreco@nvidia.com>
This commit is contained in:
Johnny Greco
2026-09-12 01:06:43 +00:00
parent 8036d8fc14
commit 5764a6b6d5
2 changed files with 37 additions and 3 deletions
+7 -2
View File
@@ -106,9 +106,14 @@ enum CounterexampleJson<'a> {
fn main() -> ExitCode {
let cancelled = Arc::new(AtomicBool::new(false));
#[cfg(unix)]
if let Err(error) =
if let Err(error) = signal_hook::flag::register_conditional_shutdown(
signal_hook::consts::signal::SIGINT,
130,
Arc::clone(&cancelled),
)
.and_then(|_| {
signal_hook::flag::register(signal_hook::consts::signal::SIGINT, Arc::clone(&cancelled))
{
}) {
let _ = writeln!(
io::stderr().lock(),
"openshell-prover: cannot install Ctrl-C handler: {error}"
+30 -1
View File
@@ -181,6 +181,35 @@ fn non_ascii_network_literals_are_unsupported_in_both_inputs() {
assert!(text.contains("non-ASCII"), "{text}");
}
#[test]
fn embedded_nul_network_literal_is_unsupported_without_panicking() {
let path = std::env::temp_dir().join(format!(
"openshell-prover-nul-selector-{}.yaml",
std::process::id()
));
fs::write(
&path,
"version: 1\nnetwork_policies:\n n:\n endpoints:\n - host: api.example.com\n port: 443\n protocol: rest\n enforcement: enforce\n rules: [{ allow: { method: \"G\\0ET\", path: '/**' } }]\n binaries: [{ path: /usr/bin/curl }]\n",
)
.expect("write NUL selector policy");
let output = run(&[
"check",
path.to_str().expect("UTF-8 temporary path"),
"--maximum",
fixture("maximum-empty.yaml").to_str().unwrap(),
"--output",
"json",
]);
fs::remove_file(path).expect("remove NUL selector policy");
assert_eq!(output.status.code(), Some(3));
assert!(output.stderr.is_empty());
let value: Value = serde_json::from_slice(&output.stdout).expect("single JSON object");
assert_eq!(value["result"], "unsupported");
assert_eq!(value["reason_code"], "unsupported_policy_shape");
assert!(value["reason"].as_str().unwrap().contains("NUL"));
}
#[test]
fn resource_exhaustion_is_inconclusive_and_returns_three() {
let path = std::env::temp_dir().join(format!(
@@ -394,13 +423,13 @@ fn sigint_interrupts_the_check_with_exit_130() {
.expect("send SIGINT");
assert!(signal.success());
let output = child.wait_with_output().expect("wait for cancelled prover");
fs::remove_dir_all(directory).expect("remove cancellation policies");
assert_eq!(output.status.code(), Some(130));
let value: Value =
serde_json::from_slice(&output.stdout).expect("structured cancellation JSON");
assert_eq!(value["result"], "inconclusive");
assert_eq!(value["reason_code"], "cancelled");
assert_eq!(value["exit_code"], 130);
fs::remove_dir_all(directory).expect("remove cancellation policies");
}
#[cfg(unix)]