@@ -197,6 +197,27 @@ describe("resolvePreferredOpenClawTmpDir", () => {
197197 expectFallsBackToOsTmpDir ( { lstatSync : vi . fn ( ( ) => makeDirStat ( { mode : 0o40777 } ) ) } ) ;
198198 } ) ;
199199
200+ it ( "repairs existing /tmp/openclaw permissions when they are too broad" , ( ) => {
201+ let preferredMode = 0o40777 ;
202+ const chmodSync = vi . fn ( ( target : string , mode : number ) => {
203+ if ( target === POSIX_OPENCLAW_TMP_DIR && mode === 0o700 ) {
204+ preferredMode = 0o40700 ;
205+ }
206+ } ) ;
207+ const warn = vi . fn ( ) ;
208+
209+ const { resolved, tmpdir } = resolveWithMocks ( {
210+ lstatSync : vi . fn ( ( ) => makeDirStat ( { mode : preferredMode } ) ) ,
211+ chmodSync,
212+ warn,
213+ } ) ;
214+
215+ expect ( resolved ) . toBe ( POSIX_OPENCLAW_TMP_DIR ) ;
216+ expect ( chmodSync ) . toHaveBeenCalledWith ( POSIX_OPENCLAW_TMP_DIR , 0o700 ) ;
217+ expect ( warn ) . toHaveBeenCalledWith ( expect . stringContaining ( "tightened permissions on temp dir" ) ) ;
218+ expect ( tmpdir ) . not . toHaveBeenCalled ( ) ;
219+ } ) ;
220+
200221 it ( "throws when fallback path is a symlink" , ( ) => {
201222 const lstatSync = symlinkTmpDirLstat ( ) ;
202223 const fallbackLstatSync = vi . fn ( ( ) => makeDirStat ( { isSymbolicLink : true , mode : 0o120777 } ) ) ;
@@ -222,6 +243,35 @@ describe("resolvePreferredOpenClawTmpDir", () => {
222243 expect ( mkdirSync ) . toHaveBeenCalledWith ( fallbackTmp ( ) , { recursive : true , mode : 0o700 } ) ;
223244 } ) ;
224245
246+ it ( "uses an unscoped fallback suffix when process uid is unavailable" , ( ) => {
247+ const tmpdirPath = "/var/fallback" ;
248+ const fallbackPath = path . join ( tmpdirPath , "openclaw" ) ;
249+
250+ const resolved = resolvePreferredOpenClawTmpDir ( {
251+ accessSync : vi . fn ( ( target : string ) => {
252+ if ( target === "/tmp" ) {
253+ throw new Error ( "read-only" ) ;
254+ }
255+ } ) ,
256+ lstatSync : vi . fn ( ( target : string ) => {
257+ if ( target === POSIX_OPENCLAW_TMP_DIR ) {
258+ throw nodeErrorWithCode ( "ENOENT" ) ;
259+ }
260+ if ( target === fallbackPath ) {
261+ return makeDirStat ( { uid : 0 , mode : 0o40777 } ) ;
262+ }
263+ return secureDirStat ( ) ;
264+ } ) ,
265+ mkdirSync : vi . fn ( ) ,
266+ chmodSync : vi . fn ( ) ,
267+ getuid : vi . fn ( ( ) => undefined ) ,
268+ tmpdir : vi . fn ( ( ) => tmpdirPath ) ,
269+ warn : vi . fn ( ) ,
270+ } ) ;
271+
272+ expect ( resolved ) . toBe ( fallbackPath ) ;
273+ } ) ;
274+
225275 it ( "repairs fallback directory permissions after create when umask makes it group-writable" , ( ) => {
226276 const fallbackPath = fallbackTmp ( ) ;
227277 let fallbackMode = 0o40775 ;
@@ -287,4 +337,25 @@ describe("resolvePreferredOpenClawTmpDir", () => {
287337 expect ( chmodSync ) . toHaveBeenCalledWith ( fallbackPath , 0o700 ) ;
288338 expect ( warn ) . toHaveBeenCalledWith ( expect . stringContaining ( "tightened permissions on temp dir" ) ) ;
289339 } ) ;
340+
341+ it ( "throws when the fallback directory cannot be created" , ( ) => {
342+ expect ( ( ) =>
343+ resolvePreferredOpenClawTmpDir ( {
344+ accessSync : readOnlyTmpAccessSync ( ) ,
345+ lstatSync : vi . fn ( ( target : string ) => {
346+ if ( target === POSIX_OPENCLAW_TMP_DIR || target === fallbackTmp ( ) ) {
347+ throw nodeErrorWithCode ( "ENOENT" ) ;
348+ }
349+ return secureDirStat ( ) ;
350+ } ) ,
351+ mkdirSync : vi . fn ( ( ) => {
352+ throw new Error ( "mkdir failed" ) ;
353+ } ) ,
354+ chmodSync : vi . fn ( ) ,
355+ getuid : vi . fn ( ( ) => 501 ) ,
356+ tmpdir : vi . fn ( ( ) => "/var/fallback" ) ,
357+ warn : vi . fn ( ) ,
358+ } ) ,
359+ ) . toThrow ( / U n a b l e t o c r e a t e f a l l b a c k O p e n C l a w t e m p d i r / ) ;
360+ } ) ;
290361} ) ;
0 commit comments