@@ -163,7 +163,7 @@ def render(
163163
164164 # Add label and value
165165 if self .desc :
166- line_parts .append (f"{ self .label } { self .desc } " )
166+ line_parts .append (f"{ self .label } : { self .desc } " )
167167 else :
168168 line_parts .append (self .label )
169169
@@ -291,6 +291,9 @@ def __init__(self, hostname: Optional[str] = None, thorough_check: bool = False)
291291 # Always add GPU info so we can see errors like "nvidia-smi not found"
292292 self .add_child (gpu_info )
293293
294+ # Add user info
295+ self .add_child (UserInfo ())
296+
294297 # Add file permissions check
295298 self .add_child (FilePermissionsInfo (thorough_check = self .thorough_check ))
296299
@@ -343,6 +346,35 @@ def _suppress_planner_warnings(self) -> None:
343346 defaults_logger .setLevel (logging .ERROR )
344347
345348
349+ class UserInfo (NodeInfo ):
350+ """User information"""
351+
352+ def __init__ (self ):
353+ # Get user info
354+ username = os .getenv ("USER" ) or os .getenv ("LOGNAME" ) or "unknown"
355+ if username == "unknown" :
356+ try :
357+ import pwd
358+
359+ username = pwd .getpwuid (os .getuid ()).pw_name
360+ except Exception :
361+ try :
362+ import subprocess
363+
364+ result = subprocess .run (
365+ ["whoami" ], capture_output = True , text = True , timeout = 5
366+ )
367+ if result .returncode == 0 :
368+ username = result .stdout .strip ()
369+ except Exception :
370+ pass
371+ uid = os .getuid ()
372+ gid = os .getgid ()
373+
374+ desc = f"user={ username } , uid={ uid } , gid={ gid } "
375+ super ().__init__ (label = "User info" , desc = desc , status = NodeStatus .INFO )
376+
377+
346378class OSInfo (NodeInfo ):
347379 """Operating system information"""
348380
@@ -717,10 +749,34 @@ def _check_permissions_unified(
717749
718750 if not recursive :
719751 # Just check directory writability
752+ # Check if running as root but directory is not owned by root
753+ is_root = os .getuid () == 0
754+ is_root_owned = False
755+ warning_symbol = ""
756+ desc_text = "writable"
757+ owner_name = None
758+
759+ if is_root :
760+ try :
761+ stat_info = os .stat (selected_path )
762+ is_root_owned = stat_info .st_uid == 0
763+ if not is_root_owned :
764+ warning_symbol = " ⚠️"
765+ # Get the owner name
766+ try :
767+ import pwd
768+
769+ owner_name = pwd .getpwuid (stat_info .st_uid ).pw_name
770+ except Exception :
771+ owner_name = f"uid={ stat_info .st_uid } "
772+ desc_text = f"writable (owned by { owner_name or 'root' } )"
773+ except Exception :
774+ desc_text = "writable (owned by unknown)"
775+
720776 results .append (
721777 NodeInfo (
722- label = f"{ label_prefix } ({ self ._replace_home_with_var (selected_path )} )" ,
723- desc = "writable" ,
778+ label = f"{ label_prefix } ({ self ._replace_home_with_var (selected_path )} ){ warning_symbol } " ,
779+ desc = desc_text ,
724780 status = NodeStatus .OK ,
725781 )
726782 )
@@ -739,9 +795,41 @@ def _check_permissions_unified(
739795 total_files , non_writable_files , "files"
740796 )
741797
798+ # Check if running as root but directory is not owned by root
799+ is_root = os .getuid () == 0
800+ is_root_owned = False
801+ warning_symbol = ""
802+ owner_name = None
803+
804+ if is_root :
805+ try :
806+ stat_info = os .stat (selected_path )
807+ is_root_owned = stat_info .st_uid == 0
808+ if not is_root_owned :
809+ warning_symbol = " ⚠️"
810+ # Get the owner name
811+ try :
812+ import pwd
813+
814+ owner_name = pwd .getpwuid (stat_info .st_uid ).pw_name
815+ except Exception :
816+ owner_name = f"uid={ stat_info .st_uid } "
817+ # Modify description to indicate ownership
818+ if "writable" in desc :
819+ desc = desc .replace (
820+ "writable" ,
821+ f"writable (owned by { owner_name or 'root' } )" ,
822+ )
823+ except Exception :
824+ # Modify description to indicate ownership
825+ if "writable" in desc :
826+ desc = desc .replace (
827+ "writable" , "writable (owned by unknown)"
828+ )
829+
742830 results .append (
743831 NodeInfo (
744- label = f"{ label_prefix } ({ self ._replace_home_with_var (selected_path )} )" ,
832+ label = f"{ label_prefix } ({ self ._replace_home_with_var (selected_path )} ){ warning_symbol } " ,
745833 desc = desc ,
746834 status = status ,
747835 )
0 commit comments