1- use qqqa:: perms:: { clear_custom_allowlist , ensure_safe_path } ;
1+ use qqqa:: perms:: { ensure_safe_path , set_custom_allowlist } ;
22use qqqa:: shell:: ShellKind ;
33use qqqa:: tools:: parse_tool_call;
44use qqqa:: tools:: read_file;
@@ -15,7 +15,10 @@ struct TempCwdGuard {
1515impl TempCwdGuard {
1616 fn new ( dir : & Path ) -> Self {
1717 static CWD_LOCK : OnceLock < Mutex < ( ) > > = OnceLock :: new ( ) ;
18- let lock = CWD_LOCK . get_or_init ( || Mutex :: new ( ( ) ) ) . lock ( ) . unwrap ( ) ;
18+ let lock = CWD_LOCK
19+ . get_or_init ( || Mutex :: new ( ( ) ) )
20+ . lock ( )
21+ . unwrap_or_else ( |poisoned| poisoned. into_inner ( ) ) ;
1922 let previous = std:: env:: current_dir ( ) . expect ( "read current dir" ) ;
2023 std:: env:: set_current_dir ( dir) . expect ( "set current dir" ) ;
2124 Self {
@@ -31,12 +34,47 @@ impl Drop for TempCwdGuard {
3134 }
3235}
3336
37+ struct EnvVarGuard {
38+ key : & ' static str ,
39+ previous : Option < String > ,
40+ }
41+
42+ impl EnvVarGuard {
43+ fn set ( key : & ' static str , value : Option < & str > ) -> Self {
44+ let previous = std:: env:: var ( key) . ok ( ) ;
45+ if let Some ( val) = value {
46+ unsafe {
47+ std:: env:: set_var ( key, val) ;
48+ }
49+ } else {
50+ unsafe {
51+ std:: env:: remove_var ( key) ;
52+ }
53+ }
54+ Self { key, previous }
55+ }
56+ }
57+
58+ impl Drop for EnvVarGuard {
59+ fn drop ( & mut self ) {
60+ if let Some ( ref val) = self . previous {
61+ unsafe {
62+ std:: env:: set_var ( self . key , val) ;
63+ }
64+ } else {
65+ unsafe {
66+ std:: env:: remove_var ( self . key ) ;
67+ }
68+ }
69+ }
70+ }
71+
3472#[ test]
3573#[ serial]
3674fn read_and_write_file_tools_and_path_safety ( ) {
3775 // Set HOME and CWD to a temp folder for deterministic safety checks.
3876 let temp = tempfile:: tempdir ( ) . unwrap ( ) ;
39- clear_custom_allowlist ( ) ;
77+ set_custom_allowlist ( Vec :: new ( ) ) ;
4078 unsafe {
4179 std:: env:: set_var ( "HOME" , temp. path ( ) ) ;
4280 }
@@ -141,39 +179,38 @@ async fn execute_command_honors_pty_force_flag() {
141179 let _cwd_guard = TempCwdGuard :: new ( temp. path ( ) ) ;
142180
143181 let probe = "env sh -lc '[ -t 1 ] && echo tty || echo notty'" ;
144- let baseline = qqqa:: tools:: execute_command:: run (
145- qqqa:: tools:: execute_command:: Args {
146- command : probe. into ( ) ,
147- cwd : None ,
148- } ,
149- true ,
150- false ,
151- ShellKind :: Posix ,
152- None ,
153- )
154- . await
155- . expect ( "baseline execute_command should succeed" ) ;
182+ let baseline = {
183+ let _disable_guard = EnvVarGuard :: set ( "QQQA_DISABLE_PTY" , Some ( "1" ) ) ;
184+ qqqa:: tools:: execute_command:: run (
185+ qqqa:: tools:: execute_command:: Args {
186+ command : probe. into ( ) ,
187+ cwd : None ,
188+ } ,
189+ true ,
190+ false ,
191+ ShellKind :: Posix ,
192+ None ,
193+ )
194+ . await
195+ . expect ( "baseline execute_command should succeed" )
196+ } ;
156197 assert ! ( baseline. contains( "notty" ) ) ;
157198
158- unsafe {
159- std:: env:: set_var ( "QQQA_FORCE_PTY" , "1" ) ;
160- }
161- let forced = qqqa:: tools:: execute_command:: run (
162- qqqa:: tools:: execute_command:: Args {
163- command : probe. into ( ) ,
164- cwd : None ,
165- } ,
166- true ,
167- false ,
168- ShellKind :: Posix ,
169- None ,
170- )
171- . await
172- . expect ( "execute_command with forced PTY should succeed" ) ;
173-
174- unsafe {
175- std:: env:: remove_var ( "QQQA_FORCE_PTY" ) ;
176- }
199+ let forced = {
200+ let _force_guard = EnvVarGuard :: set ( "QQQA_FORCE_PTY" , Some ( "1" ) ) ;
201+ qqqa:: tools:: execute_command:: run (
202+ qqqa:: tools:: execute_command:: Args {
203+ command : probe. into ( ) ,
204+ cwd : None ,
205+ } ,
206+ true ,
207+ false ,
208+ ShellKind :: Posix ,
209+ None ,
210+ )
211+ . await
212+ . expect ( "execute_command with forced PTY should succeed" )
213+ } ;
177214
178215 assert ! (
179216 forced. contains( "tty" ) ,
@@ -193,43 +230,37 @@ async fn execute_command_respects_disable_flag() {
193230 let _cwd_guard = TempCwdGuard :: new ( temp. path ( ) ) ;
194231
195232 let probe = "env sh -lc '[ -t 1 ] && echo tty || echo notty'" ;
196- unsafe {
197- std:: env:: set_var ( "QQQA_FORCE_PTY" , "1" ) ;
198- }
199- let forced = qqqa:: tools:: execute_command:: run (
200- qqqa:: tools:: execute_command:: Args {
201- command : probe. into ( ) ,
202- cwd : None ,
203- } ,
204- true ,
205- false ,
206- ShellKind :: Posix ,
207- None ,
208- )
209- . await
210- . expect ( "forced PTY should succeed" ) ;
211-
212- unsafe {
213- std:: env:: remove_var ( "QQQA_FORCE_PTY" ) ;
214- std:: env:: set_var ( "QQQA_DISABLE_PTY" , "1" ) ;
215- }
216-
217- let res = qqqa:: tools:: execute_command:: run (
218- qqqa:: tools:: execute_command:: Args {
219- command : probe. into ( ) ,
220- cwd : None ,
221- } ,
222- true ,
223- false ,
224- ShellKind :: Posix ,
225- None ,
226- )
227- . await
228- . expect ( "execute_command fallback should succeed" ) ;
233+ let forced = {
234+ let _force_guard = EnvVarGuard :: set ( "QQQA_FORCE_PTY" , Some ( "1" ) ) ;
235+ qqqa:: tools:: execute_command:: run (
236+ qqqa:: tools:: execute_command:: Args {
237+ command : probe. into ( ) ,
238+ cwd : None ,
239+ } ,
240+ true ,
241+ false ,
242+ ShellKind :: Posix ,
243+ None ,
244+ )
245+ . await
246+ . expect ( "forced PTY should succeed" )
247+ } ;
229248
230- unsafe {
231- std:: env:: remove_var ( "QQQA_DISABLE_PTY" ) ;
232- }
249+ let res = {
250+ let _disable_guard = EnvVarGuard :: set ( "QQQA_DISABLE_PTY" , Some ( "1" ) ) ;
251+ qqqa:: tools:: execute_command:: run (
252+ qqqa:: tools:: execute_command:: Args {
253+ command : probe. into ( ) ,
254+ cwd : None ,
255+ } ,
256+ true ,
257+ false ,
258+ ShellKind :: Posix ,
259+ None ,
260+ )
261+ . await
262+ . expect ( "execute_command fallback should succeed" )
263+ } ;
233264
234265 assert ! ( forced. contains( "tty" ) ) ;
235266 assert ! (
0 commit comments