mod batch;
mod grant;
mod level;
mod registry;
mod target;
mod tool_mapping;
pub use batch::{
BatchAction, BatchPermissionRequest, BatchPermissionResponse, compute_suggested_grants,
};
pub use grant::{Grant, PermissionRequest};
pub use level::PermissionLevel;
pub use registry::{
PendingPermissionInfo, PermissionError, PermissionPanelResponse, PermissionRegistry,
generate_batch_id,
};
pub use target::GrantTarget;
pub use tool_mapping::{ToolCategory, ToolPermissions, get_tool_category};
#[cfg(test)]
mod integration_tests {
use super::*;
#[test]
fn test_end_to_end_permission_check() {
let grant = Grant::read_path("/project", true);
let requests = vec![
PermissionRequest::file_read("1", "/project/src/main.rs"),
PermissionRequest::file_read("2", "/project/Cargo.toml"),
PermissionRequest::directory_read("3", "/project/src", true),
];
for request in &requests {
assert!(
grant.satisfies(request),
"Grant should satisfy request: {}",
request.id
);
}
let write_request = PermissionRequest::file_write("4", "/project/src/main.rs");
assert!(
!grant.satisfies(&write_request),
"Read grant should not satisfy write request"
);
let outside_request = PermissionRequest::file_read("5", "/other/file.rs");
assert!(
!grant.satisfies(&outside_request),
"Grant should not satisfy request outside path"
);
}
#[test]
fn test_level_hierarchy() {
let admin_grant = Grant::admin_path("/project", true);
let requests = vec![
PermissionRequest::file_read("1", "/project/file.rs"),
PermissionRequest::file_write("2", "/project/file.rs"),
PermissionRequest::new(
"3",
GrantTarget::path("/project/file.rs", false),
PermissionLevel::Execute,
"Execute",
),
PermissionRequest::new(
"4",
GrantTarget::path("/project/file.rs", false),
PermissionLevel::Admin,
"Admin",
),
];
for request in &requests {
assert!(
admin_grant.satisfies(request),
"Admin grant should satisfy {} level request",
request.required_level
);
}
}
#[test]
fn test_batch_permission_flow() {
let requests = vec![
PermissionRequest::file_read("tool-1", "/project/src/main.rs"),
PermissionRequest::file_read("tool-2", "/project/src/lib.rs"),
PermissionRequest::file_read("tool-3", "/project/Cargo.toml"),
];
let batch = BatchPermissionRequest::new("batch-1", requests.clone());
assert!(!batch.suggested_grants.is_empty());
let approved_grant = Grant::read_path("/project", true);
let response = BatchPermissionResponse::all_granted("batch-1", vec![approved_grant]);
for request in &requests {
assert!(
response.is_granted(&request.id, request),
"Request {} should be granted",
request.id
);
}
}
#[test]
fn test_different_target_types_independent() {
let path_grant = Grant::read_path("/project", true);
let domain_request =
PermissionRequest::network_access("1", "api.github.com", PermissionLevel::Read);
assert!(!path_grant.satisfies(&domain_request));
let domain_grant = Grant::domain("*", PermissionLevel::Admin);
let cmd_request = PermissionRequest::command_execute("2", "git status");
assert!(!domain_grant.satisfies(&cmd_request));
let cmd_grant = Grant::command("*", PermissionLevel::Admin);
let path_request = PermissionRequest::file_read("3", "/project/file.rs");
assert!(!cmd_grant.satisfies(&path_request));
}
#[test]
fn test_serialization_roundtrip() {
let grant = Grant::write_path("/project/src", true);
let json = serde_json::to_string(&grant).unwrap();
let deserialized: Grant = serde_json::from_str(&json).unwrap();
assert_eq!(grant.level, deserialized.level);
assert_eq!(grant.target, deserialized.target);
let request = PermissionRequest::file_write("test", "/project/src/main.rs")
.with_reason("Testing")
.with_tool("write_file");
let json = serde_json::to_string(&request).unwrap();
let deserialized: PermissionRequest = serde_json::from_str(&json).unwrap();
assert_eq!(request.id, deserialized.id);
assert_eq!(request.reason, deserialized.reason);
assert_eq!(request.tool_name, deserialized.tool_name);
}
}