168aefd415
Realign fermata around redaction (PostToolUse) as the primary security layer, with access control (PreToolUse) as supplementary write/bash protection. Remove botignore.toml — policy rules now live in .botsecrets [policy] section. Add fermata.toml as an alias for .botsecrets. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
67 lines
2.3 KiB
Rust
67 lines
2.3 KiB
Rust
use dirigent_fermata::core::{Decision, Op, Policy};
|
|
use std::fs;
|
|
use tempfile::TempDir;
|
|
|
|
fn make_project(botignore: &str, botsecrets: &str) -> TempDir {
|
|
let tmp = TempDir::new().unwrap();
|
|
if !botignore.is_empty() {
|
|
fs::write(tmp.path().join(".botignore"), botignore).unwrap();
|
|
}
|
|
if !botsecrets.is_empty() {
|
|
fs::write(tmp.path().join(".botsecrets"), botsecrets).unwrap();
|
|
}
|
|
tmp
|
|
}
|
|
|
|
#[test]
|
|
fn botignore_blocks_read() {
|
|
let tmp = make_project(".env\n", "");
|
|
let policy = Policy::load(tmp.path()).unwrap();
|
|
let target = tmp.path().join(".env");
|
|
fs::write(&target, "").unwrap();
|
|
let d = policy.check(Op::Read, &target).unwrap();
|
|
assert!(matches!(d, Decision::Deny(_)));
|
|
}
|
|
|
|
#[test]
|
|
fn botignore_blocks_write_too() {
|
|
let tmp = make_project(".env\n", "");
|
|
let policy = Policy::load(tmp.path()).unwrap();
|
|
let target = tmp.path().join(".env");
|
|
let d = policy.check(Op::Write, &target).unwrap();
|
|
assert!(matches!(d, Decision::Deny(_)));
|
|
}
|
|
|
|
#[test]
|
|
fn unmatched_path_allowed() {
|
|
let tmp = make_project(".env\n", "");
|
|
let policy = Policy::load(tmp.path()).unwrap();
|
|
let target = tmp.path().join("src/main.rs");
|
|
fs::create_dir_all(target.parent().unwrap()).unwrap();
|
|
fs::write(&target, "").unwrap();
|
|
let d = policy.check(Op::Read, &target).unwrap();
|
|
assert_eq!(d, Decision::Allow);
|
|
}
|
|
|
|
#[test]
|
|
fn policy_read_block_applies_only_to_read() {
|
|
let tmp = make_project("", "[policy.read]\npatterns = [\"secrets/**\"]\n");
|
|
let policy = Policy::load(tmp.path()).unwrap();
|
|
let target = tmp.path().join("secrets/key.pem");
|
|
fs::create_dir_all(target.parent().unwrap()).unwrap();
|
|
fs::write(&target, "").unwrap();
|
|
assert!(matches!(policy.check(Op::Read, &target).unwrap(), Decision::Deny(_)));
|
|
assert_eq!(policy.check(Op::Write, &target).unwrap(), Decision::Allow);
|
|
}
|
|
|
|
#[test]
|
|
fn policy_write_block_applies_only_to_write() {
|
|
let tmp = make_project("", "[policy.write]\npatterns = [\"vendor/**\"]\n");
|
|
let policy = Policy::load(tmp.path()).unwrap();
|
|
let target = tmp.path().join("vendor/lib.rs");
|
|
fs::create_dir_all(target.parent().unwrap()).unwrap();
|
|
fs::write(&target, "").unwrap();
|
|
assert_eq!(policy.check(Op::Read, &target).unwrap(), Decision::Allow);
|
|
assert!(matches!(policy.check(Op::Write, &target).unwrap(), Decision::Deny(_)));
|
|
}
|