@@ -152,3 +152,128 @@ func TestPromptOperation_NoTTY_Allow(t *testing.T) {
152152 t .Errorf ("expected nil for non-interactive allow, got: %v" , err )
153153 }
154154}
155+
156+ func TestSetTrustAll_ApprovesAll (t * testing.T ) {
157+ a := NewTTYApprover (& DangerousConfig {NonInteractive : strPtr ("deny" )})
158+ a .TTYPath = "/nonexistent/tty-for-test"
159+
160+ // Enable blanket trust
161+ a .SetTrustAll (true )
162+
163+ // Destructive class should auto-approve despite NonInteractive=deny
164+ if err := a .PromptCommand (Destructive , "rm -rf /" , "dangerous command" ); err != nil {
165+ t .Errorf ("expected nil with trustAll=true, got: %v" , err )
166+ }
167+
168+ // Blocked class should also auto-approve
169+ if err := a .PromptCommand (Blocked , "some blocked cmd" , "" ); err != nil {
170+ t .Errorf ("expected nil with trustAll=true, got: %v" , err )
171+ }
172+ }
173+
174+ func TestSetTrustAll_ThenDisable (t * testing.T ) {
175+ a := NewTTYApprover (& DangerousConfig {NonInteractive : strPtr ("deny" )})
176+ a .TTYPath = "/nonexistent/tty-for-test"
177+
178+ // Enable blanket trust
179+ a .SetTrustAll (true )
180+
181+ // Should be approved
182+ if err := a .PromptCommand (Destructive , "rm -rf /" , "" ); err != nil {
183+ t .Errorf ("expected nil with trustAll=true, got: %v" , err )
184+ }
185+
186+ // Disable blanket trust
187+ a .SetTrustAll (false )
188+
189+ // Should now be denied (no TTY, NonInteractive=deny)
190+ err := a .PromptCommand (Destructive , "rm -rf /" , "" )
191+ if err == nil {
192+ t .Fatal ("expected error after disabling trustAll" )
193+ }
194+ if ! strings .Contains (err .Error (), "denied" ) {
195+ t .Errorf ("expected 'denied' in error message, got: %v" , err )
196+ }
197+ }
198+
199+ func TestPromptCommand_NoTTY_NilConfigDefaultAllow (t * testing.T ) {
200+ a := NewTTYApprover (nil )
201+ a .TTYPath = "/nonexistent/tty-for-test"
202+
203+ // Nil config with no TTY → NonInteractive defaults to Allow → returns nil
204+ err := a .PromptCommand (SystemWrite , "some command" , "" )
205+ if err != nil {
206+ t .Errorf ("expected nil for nil config + no TTY, got: %v" , err )
207+ }
208+ }
209+
210+ func TestPromptCommand_NoTTY_NonInteractiveDeny_Untrusted (t * testing.T ) {
211+ a := NewTTYApprover (& DangerousConfig {NonInteractive : strPtr ("deny" )})
212+ a .TTYPath = "/nonexistent/tty-for-test"
213+
214+ // No trusted classes configure, non-interactive deny → should error
215+ err := a .PromptCommand (SystemWrite , "touch /etc/config" , "write system file" )
216+ if err == nil {
217+ t .Fatal ("expected error for non-interactive deny with no TTY" )
218+ }
219+ if ! strings .Contains (err .Error (), "denied" ) {
220+ t .Errorf ("expected 'denied' in error message, got: %v" , err )
221+ }
222+ }
223+
224+ func TestPromptCommand_TrustedClassSkipsTTY (t * testing.T ) {
225+ a := NewTTYApprover (& DangerousConfig {NonInteractive : strPtr ("deny" )})
226+ a .TTYPath = "/nonexistent/tty-for-test"
227+
228+ // Trust Destructive class
229+ a .SetTrustedClasses (map [RiskClass ]bool {Destructive : true })
230+
231+ // Trusted class is checked before TTY → should succeed even with NonInteractive=deny
232+ err := a .PromptCommand (Destructive , "rm -rf /tmp/data" , "" )
233+ if err != nil {
234+ t .Errorf ("expected nil for trusted class, got: %v" , err )
235+ }
236+
237+ // SystemWrite is NOT trusted → should be denied
238+ err = a .PromptCommand (SystemWrite , "touch /etc/config" , "" )
239+ if err == nil {
240+ t .Fatal ("expected error for untrusted class with NonInteractive=deny" )
241+ }
242+ if ! strings .Contains (err .Error (), "denied" ) {
243+ t .Errorf ("expected 'denied' in error message, got: %v" , err )
244+ }
245+ }
246+
247+ func TestPromptOperation_NoTTY_NonInteractiveDeny (t * testing.T ) {
248+ a := NewTTYApprover (& DangerousConfig {NonInteractive : strPtr ("deny" )})
249+ a .TTYPath = "/nonexistent/tty-for-test"
250+
251+ op := ToolOperation {
252+ Name : "write_file" ,
253+ Resource : "/etc/system/config" ,
254+ Risk : SystemWrite ,
255+ }
256+ err := a .PromptOperation (op )
257+ if err == nil {
258+ t .Fatal ("expected error for non-interactive deny with no TTY" )
259+ }
260+ if ! strings .Contains (err .Error (), "denied" ) {
261+ t .Errorf ("expected 'denied' in error message, got: %v" , err )
262+ }
263+ }
264+
265+ func TestPromptCommand_NoTTY_NonInteractiveDeny_SafeClass (t * testing.T ) {
266+ a := NewTTYApprover (& DangerousConfig {NonInteractive : strPtr ("deny" )})
267+ a .TTYPath = "/nonexistent/tty-for-test"
268+
269+ // Safe class is not in trusted classes but no trusted classes configured at all
270+ // so TrustedClasses map exists but is empty → Safe is not trusted
271+ // NonInteractive=deny + no TTY → should error
272+ err := a .PromptCommand (Safe , "ls" , "" )
273+ if err == nil {
274+ t .Fatal ("expected error for non-interactive deny with no TTY" )
275+ }
276+ if ! strings .Contains (err .Error (), "denied" ) {
277+ t .Errorf ("expected 'denied' in error message, got: %v" , err )
278+ }
279+ }
0 commit comments