crates/gunnar-crypt/tests/nested_gitattributes.rs
//! **A nested `.gitattributes` is plaintext on both sides** (wiring tracer B
//! 2026-10-08). The client's line `.gitattributes !filter !diff !merge` has no
//! slash, so git matches it at ANY depth and `sub/.gitattributes` is committed
//! as it is; the server allowed only the root one, so such a push was refused
//! with advice (renormalize) that could not fix it. Every `.gitattributes`
//! names filters git reads before a clone is unlocked: plaintext, at any depth.
use gunnar_crypt::policy::{check_blob, Refusal};
#[test]
fn a_gitattributes_at_any_depth_is_plaintext_and_nothing_else_is() {
let text = b"*.bin -diff\n";
for path in [
".gitattributes",
"docs/.gitattributes",
"a/b/c/.gitattributes",
] {
assert_eq!(check_blob(path, false, text), Ok(()), "{path}");
}
for path in [
"docs/.gitattributes.bak",
"docs/x.gitattributes",
"docs/notes.txt",
] {
assert!(
matches!(
check_blob(path, false, text),
Err(Refusal::Plaintext { .. })
),
"{path} is no attributes file"
);
}
assert!(
matches!(
check_blob("docs/.gitattributes", true, text),
Err(Refusal::Symlink { .. })
),
"a symlink never"
);
assert!(
gunnar_crypt::GITATTRIBUTES_LINES
.iter()
.any(|l| l.starts_with(".gitattributes ")),
"the client keeps the depth-free line the server now matches"
);
}