"""Static AST audit: refuse to run downloaded code that can touch the system."""
import ast, sys

BAD_MODULES = {'os', 'subprocess', 'socket', 'shutil', 'pickle', 'marshal', 'ctypes',
               'urllib', 'requests', 'http', 'pathlib', 'tempfile', 'multiprocessing',
               'threading', 'importlib', 'signal', 'atexit', 'webbrowser', 'ssl', 'ftplib'}
BAD_CALLS = {'exec', 'eval', 'compile', '__import__', 'open', 'input', 'breakpoint',
             'memoryview', 'globals', 'locals', 'setattr', 'delattr', 'getattr'}

src = open(sys.argv[1], encoding='utf-8').read()
tree = ast.parse(src)

imports, calls = set(), {}
for node in ast.walk(tree):
    if isinstance(node, ast.Import):
        for a in node.names:
            imports.add(a.name.split('.')[0])
    elif isinstance(node, ast.ImportFrom):
        if node.module:
            imports.add(node.module.split('.')[0])
    elif isinstance(node, ast.Call):
        f = node.func
        name = None
        if isinstance(f, ast.Name):
            name = f.id
        elif isinstance(f, ast.Attribute):
            base = f.value
            name = (base.id + '.' + f.attr) if isinstance(base, ast.Name) else '.' + f.attr
        if name:
            calls[name] = calls.get(name, 0) + 1

bad_i = imports & BAD_MODULES
bad_c = {k: v for k, v in calls.items() if k.split('.')[0] in BAD_CALLS or k in BAD_CALLS}

print('IMPORTS:', sorted(imports))
print('CALLS  :', dict(sorted(calls.items(), key=lambda kv: -kv[1])[:15]))
if bad_i or bad_c:
    print('AUDIT FAIL ->', sorted(bad_i), bad_c)
    sys.exit(1)
print('AUDIT OK (no system-touching imports or calls)')
