Coverage for src/fileaudit/cli.py: 37%

106 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-11 17:14 +0200

1""" 

2License GPL3 

3(C) 2026 Created by Maikel Mardjan - https://nocomplexity.com/ 

4FileAudit - File Security Checker 

5""" 

6import os 

7from urllib.parse import urlparse 

8 

9import fire 

10 

11from fileaudit.__about__ import __version__ 

12from fileaudit.json_check import validate_json 

13from fileaudit.targz_check import validate_tar_gz 

14from fileaudit.xml_check import validate_xml 

15from fileaudit.tar_check import validate_tar 

16from fileaudit.zip_check import validate_zip 

17from fileaudit.gz_check import validate_gz 

18from fileaudit.csv_check import validate_csv 

19from fileaudit.python_check import validate_python 

20 

21fileaudit_ascii_art = r""" 

22-------------------------------- 

23 __ _  

24|_ o | _ |_| _| o _|_ 

25| | | (/_ | ||_|(_| | |_ 

26-------------------------------- 

27""" 

28 

29# Mapping of file extensions to validation functions 

30VALIDATORS = { 

31 '.json': validate_json, 

32 '.xml': validate_xml, 

33 '.csv': validate_csv, 

34 '.py': validate_python, 

35 '.zip': validate_zip, 

36 '.tar': validate_tar, 

37 '.gz': validate_gz, 

38 '.tgz': validate_tar_gz, 

39 '.tar.gz': validate_tar_gz, 

40} 

41 

42# Supported file types for help display 

43SUPPORTED_TYPES = { 

44 'json': 'JSON files', 

45 'xml': 'XML files', 

46 'csv': 'CSV files', 

47 'python': 'Python source files', 

48 'py': 'Python source files', 

49 'zip': 'ZIP archives', 

50 'tar': 'TAR archives', 

51 'gz': 'GZIP files', 

52 'tar-gz': 'TAR.GZ archives', 

53 'tgz': 'TAR.GZ archives', 

54} 

55 

56TYPE_MAP = { 

57 'json': validate_json, 

58 'xml': validate_xml, 

59 'csv': validate_csv, 

60 'python': validate_python, 

61 'py': validate_python, 

62 'zip': validate_zip, 

63 'tar': validate_tar, 

64 'gz': validate_gz, 

65 'tar-gz': validate_tar_gz, 

66 'tgz': validate_tar_gz, 

67} 

68 

69 

70class FileAudit: 

71 """🔒 Python File Audit - Secure your Python Programs with one simple line!""" 

72 

73 def __init__(self): 

74 self.version = __version__ 

75 

76 def check(self, filepath, type=None): 

77 """ 

78 Validate a file for security issues. 

79  

80 Args: 

81 filepath: Path to file or URL to audit 

82 type: Optional manual type specification (json, xml, csv, python, zip, tar, gz, tar-gz) 

83 """ 

84 if not filepath: 

85 print("❌ Error: Please specify a file or URL to check") 

86 print("Usage: fileaudit check <FILE|URL> [--type TYPE]") 

87 return 1 

88 

89 # Check if it's a URL or local file 

90 is_url = filepath.startswith(('http://', 'https://')) 

91 

92 # If type is specified, map to validator 

93 if type: 

94 validator = TYPE_MAP.get(type.lower()) 

95 if not validator: 

96 print(f"❌ Error: Unsupported file type '{type}'") 

97 print(f"Supported types: {', '.join(sorted(TYPE_MAP.keys()))}") 

98 return 1 

99 else: 

100 # Auto-detect 

101 validator = self._detect_file_type(filepath) 

102 if not validator: 

103 print(f"❌ Error: Could not detect file type for '{filepath}'") 

104 print("Please specify file type with --type option") 

105 print(f"Supported types: {', '.join(sorted(SUPPORTED_TYPES.keys()))}") 

106 return 1 

107 

108 # Execute validation 

109 try: 

110 print(f"🔍 Auditing: {filepath}") 

111 if is_url: 

112 print(f"📡 Downloading from remote URL...") 

113 else: 

114 print(f"📁 Local file detected") 

115 

116 # Call the validator 

117 validator(filepath) 

118 print(f"✅ Security audit passed for {filepath}") 

119 return 0 

120 except Exception as e: 

121 print(f"❌ Security audit failed: {e}") 

122 return 1 

123 

124 def _detect_file_type(self, filepath): 

125 """Auto-detect file type from extension""" 

126 ext = self._get_file_extension(filepath) 

127 if ext in VALIDATORS: 

128 return VALIDATORS[ext] 

129 

130 # If no extension found or unsupported, try to detect from URL path 

131 if filepath.startswith(('http://', 'https://')): 

132 parsed = urlparse(filepath) 

133 path = parsed.path 

134 ext = self._get_file_extension(path) 

135 if ext in VALIDATORS: 

136 return VALIDATORS[ext] 

137 

138 return None 

139 

140 def _get_file_extension(self, filename): 

141 """Extract file extension, handling special cases like .tar.gz""" 

142 if filename.endswith('.tar.gz'): 

143 return '.tar.gz' 

144 # Handle URLs with query parameters 

145 if '?' in filename: 

146 filename = filename.split('?')[0] 

147 ext = os.path.splitext(filename)[1].lower() 

148 return ext 

149 

150 def version(self): 

151 """Display version information""" 

152 print(f"FileAudit version: {__version__}") 

153 

154 def help(self): 

155 """Show detailed help for using FileAudit tool""" 

156 print(fileaudit_ascii_art) 

157 print( 

158 "🔒 Python File Audit - Secure your Python Programs with one simple line!\n" 

159 ) 

160 print("Usage:") 

161 print(" fileaudit check <FILE|URL> # Auto-detect file type") 

162 print(" fileaudit check <FILE|URL> --type TYPE # Manually specify type") 

163 print(" fileaudit version # Show version") 

164 print(" fileaudit help # Show this help\n") 

165 

166 print("Supported file types (auto-detected by extension):") 

167 for ftype, description in sorted(SUPPORTED_TYPES.items()): 

168 print(f" {ftype:<12} {description}") 

169 

170 print("\nExamples:") 

171 print(" fileaudit check app.py # Auto-detect Python") 

172 print(" fileaudit check data.json # Auto-detect JSON") 

173 print(" fileaudit check https://example.com/file.zip # Remote file") 

174 print(" fileaudit check archive.tar.gz --type tar-gz # Manual override") 

175 print(" fileaudit check unknown.dat --type json # Force type") 

176 

177 print( 

178 "\n📚 Documentation: https://fileAudit.nocomplexity.com" 

179 ) 

180 print( 

181 "🔧 Explore security tools: https://simplifysecurity.nocomplexity.com/\n" 

182 ) 

183 

184 

185 

186def main(): 

187 """Entry point for the CLI application.""" 

188 import sys 

189 import os 

190 

191 if len(sys.argv) == 1: 

192 FileAudit().help() 

193 return 

194 

195 first_arg = sys.argv[1] 

196 

197 # Check if it's a URL or an existing file path 

198 is_file_or_url = ( 

199 first_arg.startswith(('http://', 'https://')) or 

200 (os.path.isfile(first_arg) and not first_arg.startswith('-')) 

201 ) 

202 

203 # Also handle if it looks like a file with extension 

204 if not is_file_or_url and '.' in first_arg and not first_arg.startswith('-'): 

205 # Make sure it's not just '.' or '..' or a directory 

206 last_part = os.path.basename(first_arg) 

207 if last_part not in ['.', '..'] and '.' in last_part[1:]: # Not starting with dot 

208 # Check if there are characters after the last dot 

209 dot_index = last_part.rfind('.') 

210 if dot_index < len(last_part) - 1: 210 ↛ 213line 210 didn't jump to line 213 because the condition on line 210 was always true

211 is_file_or_url = True 

212 

213 if is_file_or_url: 

214 sys.argv.insert(1, 'check') 

215 

216 fire.Fire(FileAudit, name='fileaudit') 

217 

218 

219if __name__ == "__main__": 219 ↛ 220line 219 didn't jump to line 220 because the condition on line 219 was never true

220 main()