Argus Lite — Code Scanner (Free) — Argus Lite — 代码扫描器(免费)
v1.0.0Argus Lite — Code Scanner(免费)。扫描单个Python文件,检测前10种最关键的安全和bug模式。这是Argus Pro功能的免费预览...
运行时依赖
安装命令
点击复制技能文档
Argus Lite — 免费代码扫描器 扫描一个Python文件,检查前10个关键的安全和错误规则。 免费版与专业版功能对比 Argus Lite(免费) Argus Pro 文件 仅1个文件 全目录递归 规则 10(关键/高) 40+,包括性能 语言 仅Python Python + JavaScript JSON输出 CI准备 CI退出代码 忽略路径 重复数据删除 基本 智能跨文件 升级:openclaw skills install argus-pro — 在ko-fi.com/occupythemilkyway获取密钥
步骤1 — 安装 pip3 install rich --break-system-packages --quiet
步骤2 — 快速安全扫描(Lite) 导入os、re 从pathlib导入Path 从rich.console导入Console 从rich.table导入Table 从rich.panel导入Panel 从rich导入box console = Console() SRC_PATH = os.environ.get("SOURCE_PATH",".").strip() src = Path(SRC_PATH) 如果src是目录: py_files = list(src.rglob(".py")) 如果没有py文件: console.print(f"[yellow]没有找到.py文件在{SRC_PATH}[/yellow]") 引发SystemExit(0) target = py_files[0] 如果有多个py文件: console.print(f"[yellow]Lite版本一次扫描一个文件。扫描:{target}\n (升级到Pro版本扫描所有{len(py_files)}文件)[/yellow]\n") 如果src是文件: target = src 否则: console.print(f"[red]未找到:{SRC_PATH}[/red]") 引发SystemExit(1)
仅检查前10个关键/高规则(Lite) RULES = [ ("PY001","critical","security", r"\beval\s\(", "eval()执行任意代码 — 关键风险。", "使用ast.literal_eval()进行安全评估。"), ("PY002","critical","security", r"\bexec\s\(", "exec()执行任意字符串作为Python代码。", "重构以消除动态执行。"), ("PY003","critical","security", r"\bpickle\.loads?\s\(", "pickle.load()与不受信任的数据 → 代码执行。", "使用json.loads()代替。"), ("PY004","high","security", r"(?i)(password|secret|api_key|token)\s=\s['\"].+['\"]","硬编码凭据检测。", "移到环境变量。"), ("PY005","high","security", r"shell\s=\sTrue", "shell=True在subprocess → 命令注入风险。", "使用列表参数:subprocess.run(['cmd','arg'])"), ("PY006","high","security", r"\.execute\s\(.(%|\.format\(|f['\"])", "潜在的SQL注入通过字符串格式化。", "使用参数化查询:cursor.execute(sql,(val,))"), ("PY009","medium","bug", r"except\s:", "裸except捕获SystemExit和KeyboardInterrupt。", "使用:except Exception:或捕获特定类型。"), ("PY016","medium","security", r"hashlib\.(md5|sha1)\s\(", "MD5/SHA1是密码学破解的。", "使用hashlib.sha256()或bcrypt进行密码。"), ("PY007","medium","bug", r"def\s+\w+\s\([^)]=\s\[\s\]", "可变默认参数[] — 跨所有调用共享。", "使用None作为默认值;在函数内部初始化列表。"), ("PY017","high","security", r"\brandom\.(random|randint|choice)\s*\(","random模块不是密码学安全的。", "使用secrets模块进行安全敏感值。"), ]
console.print(Panel.fit( f"[bold red]ð Argus Lite — 快速扫描[/bold red]\n" f"文件:[yellow]{target}[/yellow]\n" f"[dim]Lite:1个文件,10个规则 — 升级到Pro版本进行全代码库扫描[/dim]", border_style="red" ))
findings = [] 尝试: source = target.read_text(encoding="utf-8", errors="replace") 对于lineno,line在source.splitlines()中枚举(1): 对于rule_id,sev,category,pattern,message,fix在RULES中: 如果re.search(pattern,line): findings.append({"id":rule_id,"severity":sev,"category":category, "line":lineno,"code":line.strip()[:80],"message":message,"fix":fix}) 除异常e外: console.print(f"[red]读取文件错误:{e}[/red]") 引发SystemExit(1)
去重 seen,unique = set(),[] 对于f在findings中: key = (f["id"],f["line"]) 如果key不在seen中: seen.add(key) unique.append(f)
SEV_COLOUR = {"critical":"red","high":"orange3","medium":"yellow","low":"dim"} 如果没有unique: console.print(Panel( f"[green]â 没有问题在{RULES.__len__()}规则扫描中![/green]\n" f"[dim]Pro版本扫描40+规则,包括性能模式 — 升级到全覆盖。[/dim]", border_style="green" )) 否则: tbl = Table(title=f"ð {len(unique)} 个问题在{target.name}中", box=box.ROUNDED, border_style="red") tbl.add_column("ID", width=7, style="dim") tbl.add_column("Sev", width=9) tbl.add_column("Line", width=6, justify="right", style="yellow") tbl.add_column("问题", width=50) 对于fi在unique中: sc = SEV_COLOUR.get(fi["severity"],"white")