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
« 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
9import fire
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
21fileaudit_ascii_art = r"""
22--------------------------------
23 __ _
24|_ o | _ |_| _| o _|_
25| | | (/_ | ||_|(_| | |_
26--------------------------------
27"""
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}
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}
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}
70class FileAudit:
71 """🔒 Python File Audit - Secure your Python Programs with one simple line!"""
73 def __init__(self):
74 self.version = __version__
76 def check(self, filepath, type=None):
77 """
78 Validate a file for security issues.
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
89 # Check if it's a URL or local file
90 is_url = filepath.startswith(('http://', 'https://'))
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
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")
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
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]
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]
138 return None
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
150 def version(self):
151 """Display version information"""
152 print(f"FileAudit version: {__version__}")
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")
166 print("Supported file types (auto-detected by extension):")
167 for ftype, description in sorted(SUPPORTED_TYPES.items()):
168 print(f" {ftype:<12} {description}")
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")
177 print(
178 "\n📚 Documentation: https://fileAudit.nocomplexity.com"
179 )
180 print(
181 "🔧 Explore security tools: https://simplifysecurity.nocomplexity.com/\n"
182 )
186def main():
187 """Entry point for the CLI application."""
188 import sys
189 import os
191 if len(sys.argv) == 1:
192 FileAudit().help()
193 return
195 first_arg = sys.argv[1]
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 )
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
213 if is_file_or_url:
214 sys.argv.insert(1, 'check')
216 fire.Fire(FileAudit, name='fileaudit')
219if __name__ == "__main__": 219 ↛ 220line 219 didn't jump to line 220 because the condition on line 219 was never true
220 main()