@pwddd/skills-scanner 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.ts +62 -11
- package/package.json +3 -3
- package/skills/skills-scanner/scan.py +39 -6
package/index.ts
CHANGED
|
@@ -568,27 +568,78 @@ export default function register(api: any) {
|
|
|
568
568
|
|
|
569
569
|
const lines = [
|
|
570
570
|
"📋 *Skills Scanner 状态*",
|
|
571
|
+
`API 服务地址:${apiUrl}`,
|
|
571
572
|
`Python 依赖:${isVenvReady() ? "✅ 就绪" : "❌ 未就绪"}`,
|
|
572
573
|
`Python 路径:${VENV_PYTHON}`,
|
|
573
574
|
`scan.py 路径:${SCAN_SCRIPT}`,
|
|
574
575
|
`安装前扫描:${preInstallScan === "on" ? `✅ 监听中(${onUnsafe})` : "❌ 已禁用"}`,
|
|
576
|
+
`扫描策略:${policy}`,
|
|
577
|
+
`LLM 分析:${useLLM ? "✅ 启用" : "❌ 禁用"}`,
|
|
578
|
+
`行为分析:${behavioral ? "✅ 启用" : "❌ 禁用"}`,
|
|
575
579
|
`上次扫描:${state.lastScanAt ? new Date(state.lastScanAt).toLocaleString("zh-CN") : "从未"}`,
|
|
576
580
|
`上次问题 Skills:${state.lastUnsafeSkills?.length ? state.lastUnsafeSkills.join(", ") : "无"}`,
|
|
577
581
|
`扫描目录:\n${scanDirs.map(d => ` • ${d}`).join("\n")}`,
|
|
578
582
|
];
|
|
579
583
|
|
|
580
|
-
//
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
lines.push(`cisco-ai-skill-scanner 版本:${versionCheck.trim()}`);
|
|
584
|
-
} catch (err: any) {
|
|
585
|
-
lines.push(`❌ 依赖检查失败:${err.message}`);
|
|
586
|
-
|
|
587
|
-
// 尝试列出已安装的包
|
|
584
|
+
// API 健康检查
|
|
585
|
+
if (isVenvReady()) {
|
|
586
|
+
lines.push("", "🔍 *API 服务检查*");
|
|
588
587
|
try {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
588
|
+
// 调用 scan.py health 命令
|
|
589
|
+
const cmd = `"${VENV_PYTHON}" "${SCAN_SCRIPT}" --api-url "${apiUrl}" health`;
|
|
590
|
+
|
|
591
|
+
// 清除代理环境变量
|
|
592
|
+
const env = { ...process.env };
|
|
593
|
+
delete env.http_proxy;
|
|
594
|
+
delete env.https_proxy;
|
|
595
|
+
delete env.HTTP_PROXY;
|
|
596
|
+
delete env.HTTPS_PROXY;
|
|
597
|
+
delete env.all_proxy;
|
|
598
|
+
delete env.ALL_PROXY;
|
|
599
|
+
|
|
600
|
+
const { stdout, stderr } = await execAsync(cmd, { timeout: 5000, env });
|
|
601
|
+
const output = (stdout + stderr).trim();
|
|
602
|
+
|
|
603
|
+
if (output.includes("✓") || output.includes("正常")) {
|
|
604
|
+
lines.push(`API 服务:✅ 正常`);
|
|
605
|
+
|
|
606
|
+
// 尝试解析可用的分析器信息
|
|
607
|
+
if (output.includes("analyzers_available")) {
|
|
608
|
+
try {
|
|
609
|
+
// 从输出中提取 JSON(如果有的话)
|
|
610
|
+
const jsonMatch = output.match(/\{[\s\S]*\}/);
|
|
611
|
+
if (jsonMatch) {
|
|
612
|
+
const healthData = JSON.parse(jsonMatch[0]);
|
|
613
|
+
if (healthData.analyzers_available) {
|
|
614
|
+
lines.push(`可用分析器:${healthData.analyzers_available.join(", ")}`);
|
|
615
|
+
}
|
|
616
|
+
if (healthData.version) {
|
|
617
|
+
lines.push(`API 版本:${healthData.version}`);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
} catch {}
|
|
621
|
+
}
|
|
622
|
+
} else {
|
|
623
|
+
lines.push(`API 服务:❌ 不可用`);
|
|
624
|
+
lines.push(`响应:${output}`);
|
|
625
|
+
}
|
|
626
|
+
} catch (err: any) {
|
|
627
|
+
lines.push(`API 服务:❌ 连接失败`);
|
|
628
|
+
const errorMsg = err.message || err.toString();
|
|
629
|
+
if (errorMsg.includes("ECONNREFUSED") || errorMsg.includes("无法连接")) {
|
|
630
|
+
lines.push(`错误:无法连接到 ${apiUrl}`);
|
|
631
|
+
} else {
|
|
632
|
+
lines.push(`错误:${errorMsg}`);
|
|
633
|
+
}
|
|
634
|
+
lines.push("", "💡 请确保 skill-scanner-api 服务正在运行:");
|
|
635
|
+
lines.push("```");
|
|
636
|
+
lines.push("skill-scanner-api");
|
|
637
|
+
lines.push("# 或指定端口");
|
|
638
|
+
lines.push("skill-scanner-api --port 8080");
|
|
639
|
+
lines.push("```");
|
|
640
|
+
}
|
|
641
|
+
} else {
|
|
642
|
+
lines.push("", "⚠️ Python 依赖未就绪,无法检查 API 服务");
|
|
592
643
|
}
|
|
593
644
|
|
|
594
645
|
if (alerts.length > 0) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pwddd/skills-scanner",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "OpenClaw Plugin:Skills
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "OpenClaw Plugin:Skills 安全扫描、安装前拦截、安全日报(HTTP API 客户端模式)",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"files": [
|
|
7
7
|
"index.ts",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"openclaw": {
|
|
13
13
|
"extensions": ["./index.ts"]
|
|
14
14
|
},
|
|
15
|
-
"keywords": ["openclaw", "openclaw-plugin", "security", "skill-scanner"],
|
|
15
|
+
"keywords": ["openclaw", "openclaw-plugin", "security", "skill-scanner", "http-client"],
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"publishConfig": {
|
|
18
18
|
"access": "public"
|
|
@@ -57,13 +57,30 @@ class SkillScannerClient:
|
|
|
57
57
|
self.base_url = base_url.rstrip('/')
|
|
58
58
|
self.session = requests.Session()
|
|
59
59
|
|
|
60
|
-
def health_check(self) ->
|
|
61
|
-
"""
|
|
60
|
+
def health_check(self) -> Dict[str, Any]:
|
|
61
|
+
"""健康检查,返回详细信息"""
|
|
62
62
|
try:
|
|
63
63
|
response = self.session.get(f"{self.base_url}/health", timeout=5)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
response.raise_for_status()
|
|
65
|
+
return {
|
|
66
|
+
'status': 'healthy',
|
|
67
|
+
'data': response.json()
|
|
68
|
+
}
|
|
69
|
+
except requests.exceptions.ConnectionError:
|
|
70
|
+
return {
|
|
71
|
+
'status': 'unreachable',
|
|
72
|
+
'error': f'无法连接到 {self.base_url}'
|
|
73
|
+
}
|
|
74
|
+
except requests.exceptions.Timeout:
|
|
75
|
+
return {
|
|
76
|
+
'status': 'timeout',
|
|
77
|
+
'error': '请求超时'
|
|
78
|
+
}
|
|
79
|
+
except Exception as e:
|
|
80
|
+
return {
|
|
81
|
+
'status': 'error',
|
|
82
|
+
'error': str(e)
|
|
83
|
+
}
|
|
67
84
|
|
|
68
85
|
def scan_upload(
|
|
69
86
|
self,
|
|
@@ -368,11 +385,27 @@ def main():
|
|
|
368
385
|
|
|
369
386
|
try:
|
|
370
387
|
if args.command == 'health':
|
|
371
|
-
|
|
388
|
+
health_result = client.health_check()
|
|
389
|
+
|
|
390
|
+
if health_result['status'] == 'healthy':
|
|
372
391
|
print(GREEN("✓") + " API 服务正常")
|
|
392
|
+
|
|
393
|
+
# 显示详细信息
|
|
394
|
+
data = health_result.get('data', {})
|
|
395
|
+
if data:
|
|
396
|
+
print(f" 版本: {data.get('version', 'Unknown')}")
|
|
397
|
+
analyzers = data.get('analyzers_available', [])
|
|
398
|
+
if analyzers:
|
|
399
|
+
print(f" 可用分析器: {', '.join(analyzers)}")
|
|
400
|
+
|
|
401
|
+
# 输出 JSON 供程序解析
|
|
402
|
+
print(json.dumps(data))
|
|
403
|
+
|
|
373
404
|
sys.exit(0)
|
|
374
405
|
else:
|
|
375
406
|
print(RED("✗") + f" API 服务不可用: {args.api_url}")
|
|
407
|
+
error = health_result.get('error', '未知错误')
|
|
408
|
+
print(f" 错误: {error}")
|
|
376
409
|
sys.exit(1)
|
|
377
410
|
|
|
378
411
|
elif args.command == 'scan':
|