File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -36,10 +36,12 @@ def self.tmpdir
3636 # We call File.writable?, not stat.writable?, because you can't tell if a dir is actually
3737 # writable just from stat; OS mechanisms other than user/group/world bits can affect this.
3838 #
39- # However, in some container environments (e.g. Kubernetes with read-only root filesystem
40- # and emptyDir volumes), File.writable? may return false even though the directory is
41- # actually writable via mounted volumes. Fall back to stat.writable? in that case.
42- if stat . writable?
39+ # However, File.writable? can be a false negative, so preserve the
40+ # world-writable non-sticky guard below before falling back to stat.writable?.
41+ if stat . world_writable? && !stat . sticky?
42+ warn "#{ name } is world-writable: #{ dir } "
43+ next
44+ elsif stat . writable?
4345 warn "#{ name } : File.writable? reports not writable but file mode bits suggest writable, using anyway: #{ dir } "
4446 break dir
4547 end
Original file line number Diff line number Diff line change @@ -90,9 +90,32 @@ def test_writable_fallback_to_stat
9090 end
9191 end
9292
93+ def test_writable_fallback_rejects_world_writable_non_sticky
94+ omit "no meaning on this platform" if /mswin|mingw/ =~ RUBY_PLATFORM
95+ Dir . mktmpdir do |tmpdir |
96+ envs = %w[ TMPDIR TMP TEMP ]
97+ oldenv = envs . each_with_object ( { } ) { |v , h | h [ v ] = ENV . delete ( v ) }
98+ begin
99+ ENV [ envs [ 0 ] ] = tmpdir
100+ File . chmod ( 0777 , tmpdir )
101+
102+ original_writable = File . method ( :writable? )
103+ File . define_singleton_method ( :writable? ) do |path |
104+ path == tmpdir ? false : original_writable . call ( path )
105+ end
106+
107+ assert_not_equal ( tmpdir , assert_warn ( /is world-writable/ ) { Dir . tmpdir } )
108+ ensure
109+ File . define_singleton_method ( :writable? , original_writable ) if original_writable
110+ File . chmod ( 0755 , tmpdir )
111+ ENV . update ( oldenv )
112+ end
113+ end
114+ end
115+
93116 def test_writable_fallback_both_fail
94117 omit "no meaning on this platform" if /mswin|mingw/ =~ RUBY_PLATFORM
95- omit "root can write to any directory" if Process . uid == 0
118+ omit "root can write to any directory" if Process . euid == 0
96119 Dir . mktmpdir do |tmpdir |
97120 envs = %w[ TMPDIR TMP TEMP ]
98121 oldenv = envs . each_with_object ( { } ) { |v , h | h [ v ] = ENV . delete ( v ) }
You can’t perform that action at this time.
0 commit comments