libgsh: complete scenario coverage for corpus_check execution paths
Adds the ReadFailed scenario (binary path resolves to a directory so exists() succeeds but read() fails) and a scenarios coverage map at the top of the test module. The map links each test to the audit fix scenarios: - valid CID, content matches: Allowed - valid CID at admission, tampered content at execution: ContentMismatch - missing binary where directory exists: Denied (sanity preserved) - binary present but unreadable: ReadFailed (fail-closed) Plus the existing sentinels for ungoverned-CID and corpus-not-mounted. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Tyler J King <tking@guildhouse.dev>
This commit is contained in:
parent
13b393a7f1
commit
91f027ae61
1 changed files with 48 additions and 3 deletions
|
|
@ -149,11 +149,30 @@ pub fn corpus_check_with_base(corpus_cid: &str, command: &str, base_dir: &str) -
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
//! Scenario coverage map (execution half of the CID-content
|
||||||
|
//! verification audit fix):
|
||||||
|
//!
|
||||||
|
//! - **Valid CID, content matches: execution allowed** —
|
||||||
|
//! `binary_with_matching_content_is_allowed`.
|
||||||
|
//! - **Valid CID at admission, tampered content at execution:
|
||||||
|
//! execution denies** — `tampered_content_triggers_content_mismatch`.
|
||||||
|
//! - **Missing binary where directory exists: denied (existing
|
||||||
|
//! behavior preserved as sanity check)** —
|
||||||
|
//! `missing_binary_in_corpus_is_denied`.
|
||||||
|
//! - **Binary present but unreadable: denied fail-closed** —
|
||||||
|
//! `unreadable_binary_triggers_read_failed`.
|
||||||
|
//! - **Sentinel: ungoverned CID** — `ungoverned_skips_check`.
|
||||||
|
//! - **Sentinel: corpus directory not mounted on host** —
|
||||||
|
//! `missing_corpus_dir_reports_not_mounted`.
|
||||||
|
//!
|
||||||
|
//! The admission half (forged CID rejected at CRD reconcile) is
|
||||||
|
//! covered in corpus-operator::verifier.
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Write bytes to `dir/cid/name` and return the CID derived from those
|
/// Write bytes to `dir/cid/name` and return the path so the caller can
|
||||||
/// bytes so the caller can pass a matching CID for the happy path or
|
/// pass a matching CID for the happy path or a different one to
|
||||||
/// a different one to simulate tamper.
|
/// simulate tamper.
|
||||||
fn write_binary(dir: &Path, cid: &str, name: &str, contents: &[u8]) -> PathBuf {
|
fn write_binary(dir: &Path, cid: &str, name: &str, contents: &[u8]) -> PathBuf {
|
||||||
let corpus_dir = dir.join(cid);
|
let corpus_dir = dir.join(cid);
|
||||||
std::fs::create_dir_all(&corpus_dir).unwrap();
|
std::fs::create_dir_all(&corpus_dir).unwrap();
|
||||||
|
|
@ -231,4 +250,30 @@ mod tests {
|
||||||
other => panic!("expected ContentMismatch, got {other:?}"),
|
other => panic!("expected ContentMismatch, got {other:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Place a directory at the path where the binary should live; the
|
||||||
|
/// `exists()` check passes but `read()` fails. Verifies the fail-closed
|
||||||
|
/// path: an unreadable binary is denied rather than allowed.
|
||||||
|
#[test]
|
||||||
|
fn unreadable_binary_triggers_read_failed() {
|
||||||
|
let dir = tempfile::tempdir().unwrap();
|
||||||
|
let claimed = cid_of(b"any-content");
|
||||||
|
let corpus_dir = dir.path().join(&claimed);
|
||||||
|
// Make a directory at the binary path — it satisfies `exists()` but
|
||||||
|
// `read()` will fail with EISDIR or similar.
|
||||||
|
std::fs::create_dir_all(corpus_dir.join("kubectl")).unwrap();
|
||||||
|
|
||||||
|
let base = dir.path().to_str().unwrap();
|
||||||
|
match corpus_check_with_base(&claimed, "kubectl", base) {
|
||||||
|
CorpusCheckResult::ReadFailed {
|
||||||
|
corpus_cid,
|
||||||
|
command,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
assert_eq!(corpus_cid, claimed);
|
||||||
|
assert_eq!(command, "kubectl");
|
||||||
|
}
|
||||||
|
other => panic!("expected ReadFailed, got {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue