fix(policy): treat git branch listing as read-only operation
Remove 'branch' from requires_write_access() to resolve the contradiction where branch listing was classified as both read-only and write-requiring. Branch listing only enumerates local refs and has no side effects, so it should remain available under ReadOnly autonomy mode. Add regression tests: - branch_is_not_write_gated: verifies classification consistency - allows_branch_listing_in_readonly_mode: verifies end-to-end execution under ReadOnly autonomy - is_read_only_detection: now explicitly asserts branch is read-only Resolves zeroclaw-labs/zeroclaw#612 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
b5e1c3a8f5
commit
fbc26be7af
1 changed files with 40 additions and 1 deletions
|
|
@ -53,7 +53,7 @@ impl GitOperationsTool {
|
|||
fn requires_write_access(&self, operation: &str) -> bool {
|
||||
matches!(
|
||||
operation,
|
||||
"commit" | "add" | "checkout" | "branch" | "stash" | "reset" | "revert"
|
||||
"commit" | "add" | "checkout" | "stash" | "reset" | "revert"
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -666,6 +666,16 @@ mod tests {
|
|||
assert!(!tool.requires_write_access("log"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branch_is_not_write_gated() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let tool = test_tool(tmp.path());
|
||||
|
||||
// Branch listing is read-only; it must not require write access
|
||||
assert!(!tool.requires_write_access("branch"));
|
||||
assert!(tool.is_read_only("branch"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_read_only_detection() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
|
|
@ -674,6 +684,7 @@ mod tests {
|
|||
assert!(tool.is_read_only("status"));
|
||||
assert!(tool.is_read_only("diff"));
|
||||
assert!(tool.is_read_only("log"));
|
||||
assert!(tool.is_read_only("branch"));
|
||||
|
||||
assert!(!tool.is_read_only("commit"));
|
||||
assert!(!tool.is_read_only("add"));
|
||||
|
|
@ -708,6 +719,34 @@ mod tests {
|
|||
.contains("higher autonomy"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn allows_branch_listing_in_readonly_mode() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
// Initialize a git repository so the command can succeed
|
||||
std::process::Command::new("git")
|
||||
.args(["init"])
|
||||
.current_dir(tmp.path())
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
let security = Arc::new(SecurityPolicy {
|
||||
autonomy: AutonomyLevel::ReadOnly,
|
||||
..SecurityPolicy::default()
|
||||
});
|
||||
let tool = GitOperationsTool::new(security, tmp.path().to_path_buf());
|
||||
|
||||
let result = tool
|
||||
.execute(json!({"operation": "branch"}))
|
||||
.await
|
||||
.unwrap();
|
||||
// Branch listing must not be blocked by read-only autonomy
|
||||
let error_msg = result.error.as_deref().unwrap_or("");
|
||||
assert!(
|
||||
!error_msg.contains("read-only") && !error_msg.contains("higher autonomy"),
|
||||
"branch listing should not be blocked in read-only mode, got: {error_msg}"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn allows_readonly_ops_in_readonly_mode() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue