An AI agent built to do Ralph loops - plan mode for planning and ralph mode for implementing.
1use rustagent::agent::builtin_profiles;
2use rustagent::security::scope::{FileOperation, ScopeCheck};
3
4#[test]
5fn test_planner_profile_readonly_scope() {
6 let profile = builtin_profiles::planner();
7
8 // Planner has read_only: true
9 assert!(profile.security.read_only);
10 assert!(!profile.security.can_create_files);
11
12 // Should deny writes
13 let result = profile
14 .security
15 .check_path("src/main.rs", FileOperation::Write);
16 assert_eq!(result, ScopeCheck::Denied("read-only scope".to_string()));
17
18 // Should allow reads
19 let result = profile
20 .security
21 .check_path("src/main.rs", FileOperation::Read);
22 assert_eq!(result, ScopeCheck::Allowed);
23
24 // Should deny file creation (read-only takes precedence)
25 let result = profile
26 .security
27 .check_path("src/newfile.rs", FileOperation::Create);
28 assert!(matches!(result, ScopeCheck::Denied(_)));
29}
30
31#[test]
32fn test_coder_profile_writable_scope() {
33 let profile = builtin_profiles::coder();
34
35 // Coder should allow writes
36 assert!(!profile.security.read_only);
37 assert!(profile.security.can_create_files);
38
39 // Should allow writes
40 let result = profile
41 .security
42 .check_path("src/main.rs", FileOperation::Write);
43 assert_eq!(result, ScopeCheck::Allowed);
44
45 // Should allow reads
46 let result = profile
47 .security
48 .check_path("src/main.rs", FileOperation::Read);
49 assert_eq!(result, ScopeCheck::Allowed);
50
51 // Should allow file creation
52 let result = profile
53 .security
54 .check_path("src/newfile.rs", FileOperation::Create);
55 assert_eq!(result, ScopeCheck::Allowed);
56}
57
58#[test]
59fn test_coder_profile_commands() {
60 let profile = builtin_profiles::coder();
61
62 // Coder allows cargo commands
63 let result = profile.security.check_command("cargo test");
64 assert_eq!(result, ScopeCheck::Allowed);
65
66 // Coder allows any command (wildcard)
67 let result = profile.security.check_command("any command");
68 assert_eq!(result, ScopeCheck::Allowed);
69}
70
71#[test]
72fn test_reviewer_profile_readonly_scope() {
73 let profile = builtin_profiles::reviewer();
74
75 // Reviewer has read_only: true
76 assert!(profile.security.read_only);
77 assert!(!profile.security.can_create_files);
78
79 // Should deny writes
80 let result = profile
81 .security
82 .check_path("src/main.rs", FileOperation::Write);
83 assert_eq!(result, ScopeCheck::Denied("read-only scope".to_string()));
84
85 // Should allow reads
86 let result = profile
87 .security
88 .check_path("src/main.rs", FileOperation::Read);
89 assert_eq!(result, ScopeCheck::Allowed);
90}
91
92#[test]
93fn test_researcher_profile_readonly_scope() {
94 let profile = builtin_profiles::researcher();
95
96 // Researcher has read_only: true
97 assert!(profile.security.read_only);
98 assert!(!profile.security.can_create_files);
99
100 // Should deny writes
101 let result = profile
102 .security
103 .check_path("src/main.rs", FileOperation::Write);
104 assert_eq!(result, ScopeCheck::Denied("read-only scope".to_string()));
105
106 // Should allow reads
107 let result = profile
108 .security
109 .check_path("src/main.rs", FileOperation::Read);
110 assert_eq!(result, ScopeCheck::Allowed);
111}
112
113#[test]
114fn test_tester_profile_writable_scope() {
115 let profile = builtin_profiles::tester();
116
117 // Tester should allow writes (for writing tests)
118 assert!(!profile.security.read_only);
119 assert!(profile.security.can_create_files);
120
121 // Should allow writes
122 let result = profile
123 .security
124 .check_path("tests/test.rs", FileOperation::Write);
125 assert_eq!(result, ScopeCheck::Allowed);
126
127 // Should allow file creation
128 let result = profile
129 .security
130 .check_path("tests/newtest.rs", FileOperation::Create);
131 assert_eq!(result, ScopeCheck::Allowed);
132}
133
134#[test]
135fn test_all_profiles_have_wildcard_paths() {
136 // All built-in profiles allow wildcard paths for maximum flexibility
137 let profiles = vec![
138 builtin_profiles::planner(),
139 builtin_profiles::coder(),
140 builtin_profiles::reviewer(),
141 builtin_profiles::tester(),
142 builtin_profiles::researcher(),
143 ];
144
145 for profile in profiles {
146 // All should have wildcard in allowed_paths
147 assert!(
148 profile.security.allowed_paths.contains(&"*".to_string()),
149 "Profile {} missing wildcard in allowed_paths",
150 profile.name
151 );
152
153 // All should have wildcard in allowed_commands
154 assert!(
155 profile.security.allowed_commands.contains(&"*".to_string()),
156 "Profile {} missing wildcard in allowed_commands",
157 profile.name
158 );
159
160 // All should deny network access by default
161 assert_eq!(
162 profile.security.check_network(),
163 ScopeCheck::Denied("network access not allowed".to_string()),
164 "Profile {} should deny network access",
165 profile.name
166 );
167 }
168}