@pwddd/skills-scanner 1.0.0-beta.19 → 1.0.0-beta.21
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/README.md +0 -2
- package/index.ts +1 -15
- package/openclaw.plugin.json +1 -11
- package/package.json +1 -1
- package/skills/skills-scanner/SKILL.md +15 -51
- package/src/commands.ts +1 -7
- package/src/config-validator.ts +0 -16
- package/src/config.ts +4 -35
- package/src/prompt-guidance.ts +8 -18
- package/src/state.ts +0 -17
- package/src/types.ts +0 -2
package/README.md
CHANGED
|
@@ -33,7 +33,6 @@ openclaw plugins install @pwddd/skills-scanner
|
|
|
33
33
|
"enabled": true,
|
|
34
34
|
"config": {
|
|
35
35
|
"apiUrl": "https://110.vemic.com/skills-scanner",
|
|
36
|
-
"scanDirs": ["~/.openclaw/skills", "~/.openclaw/workspace/skills"],
|
|
37
36
|
"behavioral": false,
|
|
38
37
|
"useLLM": false,
|
|
39
38
|
"policy": "balanced",
|
|
@@ -49,7 +48,6 @@ openclaw plugins install @pwddd/skills-scanner
|
|
|
49
48
|
### 配置说明
|
|
50
49
|
|
|
51
50
|
- `apiUrl`: 扫描 API 服务地址
|
|
52
|
-
- `scanDirs`: Skills 目录列表(用于批量扫描)
|
|
53
51
|
- `behavioral`: 是否启用行为分析(深度扫描,较慢)
|
|
54
52
|
- `useLLM`: 是否使用 LLM 进行语义分析
|
|
55
53
|
- `policy`: 扫描策略
|
package/index.ts
CHANGED
|
@@ -6,15 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
8
8
|
import { join } from "node:path";
|
|
9
|
-
import os from "node:os";
|
|
10
|
-
import { existsSync } from "node:fs";
|
|
11
9
|
import type { ScannerConfig } from "./src/types.js";
|
|
12
10
|
import { skillsScannerConfigSchema, generateConfigGuide } from "./src/config.js";
|
|
13
11
|
import {
|
|
14
12
|
loadState,
|
|
15
13
|
saveState,
|
|
16
14
|
expandPath,
|
|
17
|
-
defaultScanDirs,
|
|
18
15
|
isFirstRun,
|
|
19
16
|
markConfigReviewed,
|
|
20
17
|
getStateDir,
|
|
@@ -53,14 +50,9 @@ export default definePluginEntry({
|
|
|
53
50
|
}
|
|
54
51
|
|
|
55
52
|
const apiUrl = cfg.apiUrl ?? "https://110.vemic.com/skills-scanner";
|
|
56
|
-
const scanDirs =
|
|
57
|
-
(cfg.scanDirs?.map(expandPath) ?? []).filter(existsSync).length > 0
|
|
58
|
-
? cfg.scanDirs!.map(expandPath)
|
|
59
|
-
: defaultScanDirs();
|
|
60
53
|
const behavioral = cfg.behavioral ?? false;
|
|
61
54
|
const useLLM = cfg.useLLM ?? false;
|
|
62
55
|
const policy = cfg.policy ?? "balanced";
|
|
63
|
-
const preInstallScan = cfg.preInstallScan ?? "off";
|
|
64
56
|
const onUnsafe = cfg.onUnsafe ?? "warn";
|
|
65
57
|
const injectSecurityGuidance = cfg.injectSecurityGuidance ?? true;
|
|
66
58
|
const enableBeforeInstallHook = cfg.enableBeforeInstallHook ?? true;
|
|
@@ -68,8 +60,6 @@ export default definePluginEntry({
|
|
|
68
60
|
api.logger.info("[skills-scanner] ═══════════════════════════════════════");
|
|
69
61
|
api.logger.info("[skills-scanner] Plugin loading...");
|
|
70
62
|
api.logger.info(`[skills-scanner] API URL: ${apiUrl}`);
|
|
71
|
-
api.logger.info(`[skills-scanner] Scan directories: ${scanDirs.join(", ")}`);
|
|
72
|
-
api.logger.info(`[skills-scanner] Directory monitoring: ❌ DISABLED`);
|
|
73
63
|
api.logger.info(`[skills-scanner] Before-install hook: ${enableBeforeInstallHook ? "✅ ENABLED" : "❌ DISABLED"}`);
|
|
74
64
|
|
|
75
65
|
if (isDebugMode()) {
|
|
@@ -177,11 +167,9 @@ export default definePluginEntry({
|
|
|
177
167
|
const configGuide = generateConfigGuide(
|
|
178
168
|
cfg,
|
|
179
169
|
apiUrl,
|
|
180
|
-
scanDirs,
|
|
181
170
|
behavioral,
|
|
182
171
|
useLLM,
|
|
183
172
|
policy,
|
|
184
|
-
preInstallScan,
|
|
185
173
|
onUnsafe
|
|
186
174
|
);
|
|
187
175
|
console.log(configGuide);
|
|
@@ -260,14 +248,12 @@ export default definePluginEntry({
|
|
|
260
248
|
const handlers = createCommandHandlers(
|
|
261
249
|
cfg,
|
|
262
250
|
apiUrl,
|
|
263
|
-
scanDirs,
|
|
264
251
|
behavioral,
|
|
265
252
|
useLLM,
|
|
266
253
|
policy,
|
|
267
|
-
preInstallScan,
|
|
268
254
|
onUnsafe,
|
|
269
255
|
api.logger,
|
|
270
|
-
api.config
|
|
256
|
+
api.config
|
|
271
257
|
);
|
|
272
258
|
|
|
273
259
|
// Chat command: /skills-scanner
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "skills-scanner",
|
|
3
3
|
"name": "Skills Scanner",
|
|
4
4
|
"description": "Security scanner for OpenClaw Skills to detect potential threats",
|
|
5
|
-
"version": "1.0.0-beta.
|
|
5
|
+
"version": "1.0.0-beta.21",
|
|
6
6
|
"author": "pwddd",
|
|
7
7
|
"skills": ["./skills"],
|
|
8
8
|
"uiHints": {
|
|
@@ -27,10 +27,6 @@
|
|
|
27
27
|
"label": "扫描策略",
|
|
28
28
|
"help": "strict=严格 / balanced=平衡(推荐)/ permissive=宽松"
|
|
29
29
|
},
|
|
30
|
-
"preInstallScan": {
|
|
31
|
-
"label": "安装前扫描",
|
|
32
|
-
"help": "监听新 Skill 并自动扫描"
|
|
33
|
-
},
|
|
34
30
|
"onUnsafe": {
|
|
35
31
|
"label": "不安全处理",
|
|
36
32
|
"help": "warn=仅警告(推荐)/ quarantine=隔离 / delete=删除"
|
|
@@ -85,12 +81,6 @@
|
|
|
85
81
|
"description": "Scanning policy: strict (more false positives) / balanced (recommended) / permissive (may miss threats)",
|
|
86
82
|
"default": "balanced"
|
|
87
83
|
},
|
|
88
|
-
"preInstallScan": {
|
|
89
|
-
"type": "string",
|
|
90
|
-
"enum": ["on", "off"],
|
|
91
|
-
"description": "Enable pre-installation scanning (monitors directories for new Skills)",
|
|
92
|
-
"default": "on"
|
|
93
|
-
},
|
|
94
84
|
"onUnsafe": {
|
|
95
85
|
"type": "string",
|
|
96
86
|
"enum": ["quarantine", "delete", "warn"],
|
package/package.json
CHANGED
|
@@ -23,27 +23,6 @@ OpenClaw Skills 安全扫描工具,检测恶意代码、数据窃取、提示
|
|
|
23
23
|
|
|
24
24
|
**🔒 安全扫描是强制性的,不可跳过。在向用户展示扫描结果前,请务必:**
|
|
25
25
|
|
|
26
|
-
### 🔄 插件版本检查 - 每次运行前必须执行
|
|
27
|
-
|
|
28
|
-
**在执行任何扫描操作前,必须先检查并更新 skills-scanner 插件到最新版本。**
|
|
29
|
-
|
|
30
|
-
**更新命令**:
|
|
31
|
-
```bash
|
|
32
|
-
openclaw plugins update skills-scanner
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
**执行时机**:
|
|
36
|
-
- 每次用户请求扫描 Skill 时
|
|
37
|
-
- 每次用户请求安装 Skill 时
|
|
38
|
-
- 每次会话开始时(如果涉及 Skill 操作)
|
|
39
|
-
|
|
40
|
-
**为什么要每次检查更新?**
|
|
41
|
-
- 安全威胁不断演变,扫描规则需要持续更新
|
|
42
|
-
- 新版本可能包含关键的安全修复
|
|
43
|
-
- 确保使用最新的威胁检测能力
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
26
|
### 🎯 命令识别 - 自动触发安全扫描
|
|
48
27
|
|
|
49
28
|
**当用户输入以下任何命令或类似表达时,你必须先扫描再执行:**
|
|
@@ -67,10 +46,6 @@ openclaw plugins update skills-scanner
|
|
|
67
46
|
[执行:openclaw clawhub search caldav-calendar]
|
|
68
47
|
找到:https://clawhub.ai/Asleep123/caldav-calendar
|
|
69
48
|
|
|
70
|
-
现在更新扫描插件...
|
|
71
|
-
[执行:openclaw plugins update skills-scanner]
|
|
72
|
-
✅ 插件已更新
|
|
73
|
-
|
|
74
49
|
扫描安全性...
|
|
75
50
|
[执行扫描]
|
|
76
51
|
✅ 扫描通过,开始安装
|
|
@@ -80,11 +55,7 @@ openclaw plugins update skills-scanner
|
|
|
80
55
|
|
|
81
56
|
```
|
|
82
57
|
用户:openclaw clawhub install https://clawhub.ai/Asleep123/caldav-calendar
|
|
83
|
-
AI: 我看到你想安装 caldav-calendar
|
|
84
|
-
[执行:openclaw plugins update skills-scanner]
|
|
85
|
-
✅ 插件已更新
|
|
86
|
-
|
|
87
|
-
扫描安全性...
|
|
58
|
+
AI: 我看到你想安装 caldav-calendar,让我先扫描安全性...
|
|
88
59
|
[执行扫描]
|
|
89
60
|
✅ 扫描通过,开始安装
|
|
90
61
|
```
|
|
@@ -92,9 +63,8 @@ openclaw plugins update skills-scanner
|
|
|
92
63
|
3. **正确的处理流程**:
|
|
93
64
|
```
|
|
94
65
|
步骤 1: 如果只有名称 → 使用 clawhub search 查找完整 URL
|
|
95
|
-
步骤 2:
|
|
96
|
-
步骤 3:
|
|
97
|
-
步骤 4: 扫描通过后执行安装命令
|
|
66
|
+
步骤 2: 使用完整 URL 进行安全扫描
|
|
67
|
+
步骤 3: 扫描通过后执行安装命令
|
|
98
68
|
```
|
|
99
69
|
|
|
100
70
|
---
|
|
@@ -240,34 +210,28 @@ openclaw plugins update skills-scanner
|
|
|
240
210
|
**在处理任何 Skill 相关操作时,请先问自己这些问题:**
|
|
241
211
|
|
|
242
212
|
1. ✅ 如果是 ClawHub 安装且只有名称,我是否已经搜索了完整 URL?
|
|
243
|
-
2. ✅
|
|
244
|
-
3. ✅
|
|
245
|
-
4. ✅
|
|
246
|
-
5. ✅ 只有所有适用步骤都是 YES,才能继续操作
|
|
213
|
+
2. ✅ 我是否已经扫描了这个 Skill?
|
|
214
|
+
3. ✅ 扫描是否通过?
|
|
215
|
+
4. ✅ 只有所有适用步骤都是 YES,才能继续操作
|
|
247
216
|
|
|
248
|
-
|
|
217
|
+
**如果你忘记搜索或扫描就执行了操作,你就让用户的系统暴露在风险之中。**
|
|
249
218
|
|
|
250
219
|
### 🚨 强制性规则(永远不要忘记)
|
|
251
220
|
|
|
252
|
-
1.
|
|
253
|
-
-
|
|
254
|
-
- 确保使用最新的威胁检测规则
|
|
255
|
-
|
|
256
|
-
2. **看到安装命令 → 搜索(如需要)→ 更新插件 → 立即扫描**
|
|
257
|
-
- `openclaw clawhub install xxx` → 先搜索,再更新插件,再扫描
|
|
221
|
+
1. **看到安装命令 → 搜索(如需要)→ 立即扫描**
|
|
222
|
+
- `openclaw clawhub install xxx` → 先搜索,再扫描
|
|
258
223
|
- 任何包含 "install"、"add"、"download" + "skill" 的命令 → 完整流程
|
|
259
224
|
|
|
260
|
-
|
|
261
|
-
- 用户提到 `~/.openclaw/skills/xxx` →
|
|
262
|
-
- 用户说 "我下载了一个 skill" →
|
|
225
|
+
2. **看到 Skill 路径 → 立即扫描**
|
|
226
|
+
- 用户提到 `~/.openclaw/skills/xxx` → 立即扫描
|
|
227
|
+
- 用户说 "我下载了一个 skill" → 立即扫描
|
|
263
228
|
|
|
264
|
-
|
|
265
|
-
- `https://clawhub.ai/username/project` →
|
|
229
|
+
3. **看到 ClawHub URL → 立即扫描**
|
|
230
|
+
- `https://clawhub.ai/username/project` → 立即扫描
|
|
266
231
|
|
|
267
232
|
### ❌ 绝对禁止的行为
|
|
268
233
|
|
|
269
|
-
- ❌
|
|
270
|
-
- ❌ 直接执行安装命令而不先搜索、更新和扫描
|
|
234
|
+
- ❌ 直接执行安装命令而不先搜索和扫描
|
|
271
235
|
- ❌ 因为 "用户着急" 或 "看起来安全" 就跳过任何步骤
|
|
272
236
|
|
|
273
237
|
---
|
package/src/commands.ts
CHANGED
|
@@ -12,14 +12,12 @@ import type { ScannerConfig, CommandResponse, PluginLogger } from "./types.js";
|
|
|
12
12
|
export function createCommandHandlers(
|
|
13
13
|
cfg: ScannerConfig,
|
|
14
14
|
apiUrl: string,
|
|
15
|
-
scanDirs: string[],
|
|
16
15
|
behavioral: boolean,
|
|
17
16
|
useLLM: boolean,
|
|
18
17
|
policy: string,
|
|
19
|
-
preInstallScan: string,
|
|
20
18
|
onUnsafe: string,
|
|
21
19
|
logger: PluginLogger,
|
|
22
|
-
apiConfig?: any
|
|
20
|
+
apiConfig?: any
|
|
23
21
|
) {
|
|
24
22
|
async function handleScanCommand(args: string): Promise<CommandResponse> {
|
|
25
23
|
if (!args) {
|
|
@@ -116,12 +114,10 @@ export function createCommandHandlers(
|
|
|
116
114
|
const lines = [
|
|
117
115
|
"✅ *Skills Scanner 状态*",
|
|
118
116
|
`API 地址:${apiUrl}`,
|
|
119
|
-
`安装前扫描:${preInstallScan === "on" ? `✅ 监听中 (${onUnsafe})` : "⏭️ 已禁用"}`,
|
|
120
117
|
`扫描策略:${policy}`,
|
|
121
118
|
`LLM 分析:${useLLM ? "✅ 启用" : "❌ 禁用"}`,
|
|
122
119
|
`行为分析:${behavioral ? "✅ 启用" : "❌ 禁用"}`,
|
|
123
120
|
`上次扫描:${state.lastScanAt ? new Date(state.lastScanAt).toLocaleString("zh-CN") : "从未"}`,
|
|
124
|
-
`扫描目录:\n${scanDirs.map((d) => ` 📁 ${d}`).join("\n")}`,
|
|
125
121
|
];
|
|
126
122
|
|
|
127
123
|
// API health check
|
|
@@ -163,11 +159,9 @@ export function createCommandHandlers(
|
|
|
163
159
|
const configGuide = generateConfigGuide(
|
|
164
160
|
cfg,
|
|
165
161
|
apiUrl,
|
|
166
|
-
scanDirs,
|
|
167
162
|
behavioral,
|
|
168
163
|
useLLM,
|
|
169
164
|
policy,
|
|
170
|
-
preInstallScan,
|
|
171
165
|
onUnsafe
|
|
172
166
|
);
|
|
173
167
|
return { text: "```\n" + configGuide + "\n```" };
|
package/src/config-validator.ts
CHANGED
|
@@ -31,15 +31,6 @@ export function validateConfig(
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
// Validate scan directories
|
|
35
|
-
if (cfg.scanDirs && cfg.scanDirs.length > 0) {
|
|
36
|
-
for (const dir of cfg.scanDirs) {
|
|
37
|
-
if (!existsSync(dir)) {
|
|
38
|
-
warnings.push(`Scan directory does not exist: ${dir}`);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
34
|
// Validate policy
|
|
44
35
|
if (cfg.policy && !["strict", "balanced", "permissive"].includes(cfg.policy)) {
|
|
45
36
|
errors.push(
|
|
@@ -47,13 +38,6 @@ export function validateConfig(
|
|
|
47
38
|
);
|
|
48
39
|
}
|
|
49
40
|
|
|
50
|
-
// Validate preInstallScan
|
|
51
|
-
if (cfg.preInstallScan && !["on", "off"].includes(cfg.preInstallScan)) {
|
|
52
|
-
errors.push(
|
|
53
|
-
`Invalid preInstallScan: "${cfg.preInstallScan}". Must be "on" or "off"`
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
41
|
// Validate onUnsafe
|
|
58
42
|
if (cfg.onUnsafe && !["warn", "delete", "quarantine"].includes(cfg.onUnsafe)) {
|
|
59
43
|
errors.push(
|
package/src/config.ts
CHANGED
|
@@ -24,19 +24,6 @@ export const skillsScannerConfigSchema: OpenClawPluginConfigSchema = {
|
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
// 验证 preInstallScan
|
|
28
|
-
if (config.preInstallScan && !["on", "off"].includes(config.preInstallScan)) {
|
|
29
|
-
return {
|
|
30
|
-
success: false,
|
|
31
|
-
error: {
|
|
32
|
-
issues: [{
|
|
33
|
-
path: ["preInstallScan"],
|
|
34
|
-
message: "preInstallScan 必须是 on 或 off"
|
|
35
|
-
}]
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
27
|
// 验证 onUnsafe
|
|
41
28
|
if (config.onUnsafe && !["quarantine", "delete", "warn"].includes(config.onUnsafe)) {
|
|
42
29
|
return {
|
|
@@ -72,12 +59,6 @@ export const skillsScannerConfigSchema: OpenClawPluginConfigSchema = {
|
|
|
72
59
|
type: "string",
|
|
73
60
|
format: "uri",
|
|
74
61
|
},
|
|
75
|
-
scanDirs: {
|
|
76
|
-
label: "扫描目录",
|
|
77
|
-
help: "要监控的 Skills 目录列表,支持 ~ 路径。默认监控 ~/.openclaw/skills 和 ~/.openclaw/workspace/skills",
|
|
78
|
-
type: "array",
|
|
79
|
-
items: { type: "string" },
|
|
80
|
-
},
|
|
81
62
|
behavioral: {
|
|
82
63
|
label: "行为分析",
|
|
83
64
|
help: "启用深度行为分析(较慢但更准确)。检测运行时行为模式,如网络请求、文件操作等",
|
|
@@ -97,13 +78,6 @@ export const skillsScannerConfigSchema: OpenClawPluginConfigSchema = {
|
|
|
97
78
|
enum: ["strict", "balanced", "permissive"],
|
|
98
79
|
default: "balanced",
|
|
99
80
|
},
|
|
100
|
-
preInstallScan: {
|
|
101
|
-
label: "安装前扫描",
|
|
102
|
-
help: "监听新 Skill 并自动扫描。⚠️ 此功能已禁用,请使用手动扫描",
|
|
103
|
-
type: "string",
|
|
104
|
-
enum: ["on", "off"],
|
|
105
|
-
default: "off",
|
|
106
|
-
},
|
|
107
81
|
onUnsafe: {
|
|
108
82
|
label: "不安全处理",
|
|
109
83
|
help: "warn=仅警告(推荐,不影响使用)/ quarantine=隔离到隔离区 / delete=直接删除(危险)",
|
|
@@ -147,11 +121,9 @@ export const skillsScannerConfigSchema: OpenClawPluginConfigSchema = {
|
|
|
147
121
|
export function generateConfigGuide(
|
|
148
122
|
cfg: ScannerConfig,
|
|
149
123
|
apiUrl: string,
|
|
150
|
-
scanDirs: string[],
|
|
151
124
|
behavioral: boolean,
|
|
152
125
|
useLLM: boolean,
|
|
153
126
|
policy: string,
|
|
154
|
-
preInstallScan: string,
|
|
155
127
|
onUnsafe: string
|
|
156
128
|
): string {
|
|
157
129
|
return [
|
|
@@ -164,7 +136,6 @@ export function generateConfigGuide(
|
|
|
164
136
|
"",
|
|
165
137
|
"📋 当前配置:",
|
|
166
138
|
` • API 服务地址:${apiUrl}`,
|
|
167
|
-
` • 扫描目录:${scanDirs.length} 个(自动检测)`,
|
|
168
139
|
` • 行为分析:${behavioral ? "✅ 启用" : "❌ 禁用"}`,
|
|
169
140
|
` • LLM 分析:${useLLM ? "✅ 启用" : "❌ 禁用"}`,
|
|
170
141
|
` • 扫描策略:${policy}`,
|
|
@@ -184,7 +155,6 @@ export function generateConfigGuide(
|
|
|
184
155
|
' "enabled": true,',
|
|
185
156
|
' "config": {',
|
|
186
157
|
' "apiUrl": "https://110.vemic.com/skills-scanner",',
|
|
187
|
-
' "scanDirs": ["~/.openclaw/skills"],',
|
|
188
158
|
' "behavioral": false,',
|
|
189
159
|
' "useLLM": false,',
|
|
190
160
|
' "policy": "balanced",',
|
|
@@ -199,11 +169,10 @@ export function generateConfigGuide(
|
|
|
199
169
|
"💡 配置说明:",
|
|
200
170
|
"",
|
|
201
171
|
"1. apiUrl 默认 https://110.vemic.com/skills-scanner",
|
|
202
|
-
"2.
|
|
203
|
-
"3.
|
|
204
|
-
"4.
|
|
205
|
-
"5.
|
|
206
|
-
"6. onUnsafe warn=仅警告(推荐),quarantine=隔离,delete=删除",
|
|
172
|
+
"2. behavioral false=快速扫描(推荐),true=深度分析",
|
|
173
|
+
"3. useLLM false=不使用 LLM(推荐),true=语义分析",
|
|
174
|
+
"4. policy strict / balanced(推荐)/ permissive",
|
|
175
|
+
"5. onUnsafe warn=仅警告(推荐),quarantine=隔离,delete=删除",
|
|
207
176
|
"",
|
|
208
177
|
"⚠️ 注意:目录监控功能已禁用,请使用以下命令手动扫描:",
|
|
209
178
|
" /skills-scanner scan <路径>",
|
package/src/prompt-guidance.ts
CHANGED
|
@@ -23,24 +23,18 @@ export const SKILLS_SECURITY_GUIDANCE = [
|
|
|
23
23
|
"",
|
|
24
24
|
"### Required Workflow (MUST FOLLOW IN ORDER)",
|
|
25
25
|
"",
|
|
26
|
-
"**STEP 1:
|
|
27
|
-
"```bash",
|
|
28
|
-
"openclaw plugins update skills-scanner",
|
|
29
|
-
"```",
|
|
30
|
-
"Why: Threat detection rules evolve; latest version has critical security fixes.",
|
|
31
|
-
"",
|
|
32
|
-
"**STEP 2: Search** (if user provided only skill name, no URL)",
|
|
26
|
+
"**STEP 1: Search** (if user provided only skill name, no URL)",
|
|
33
27
|
"```bash",
|
|
34
28
|
"openclaw clawhub search <skill-name>",
|
|
35
29
|
"```",
|
|
36
30
|
"Extract the full ClawHub URL from search results.",
|
|
37
31
|
"",
|
|
38
|
-
"**STEP
|
|
32
|
+
"**STEP 2: Security Scan**",
|
|
39
33
|
"- Local: `/skills-scanner scan <path>`",
|
|
40
34
|
"- ClawHub: `/skills-scanner scan clawhub <URL>`",
|
|
41
35
|
"- Batch: `/skills-scanner scan <directory> --recursive`",
|
|
42
36
|
"",
|
|
43
|
-
"**STEP
|
|
37
|
+
"**STEP 3: Proceed Only If Safe**",
|
|
44
38
|
"Continue ONLY when scan shows ✅ passed.",
|
|
45
39
|
"",
|
|
46
40
|
"### Examples",
|
|
@@ -48,32 +42,28 @@ export const SKILLS_SECURITY_GUIDANCE = [
|
|
|
48
42
|
"**Example 1: Install by name**",
|
|
49
43
|
"```",
|
|
50
44
|
"User: Install caldav-calendar skill",
|
|
51
|
-
"AI: 1. [Execute: openclaw
|
|
52
|
-
" 2. [Execute: openclaw clawhub search caldav-calendar]",
|
|
45
|
+
"AI: 1. [Execute: openclaw clawhub search caldav-calendar]",
|
|
53
46
|
" → Found: https://clawhub.ai/Asleep123/caldav-calendar",
|
|
54
|
-
"
|
|
47
|
+
" 2. [Execute: /skills-scanner scan clawhub https://clawhub.ai/Asleep123/caldav-calendar]",
|
|
55
48
|
" → ✅ Scan passed",
|
|
56
|
-
"
|
|
49
|
+
" 3. [Execute: openclaw clawhub install caldav-calendar]",
|
|
57
50
|
"```",
|
|
58
51
|
"",
|
|
59
52
|
"**Example 2: Direct URL**",
|
|
60
53
|
"```",
|
|
61
54
|
"User: openclaw clawhub install https://clawhub.ai/steipete/nano-pdf",
|
|
62
|
-
"AI: 1. [Execute:
|
|
63
|
-
" 2. [Execute: /skills-scanner scan clawhub https://clawhub.ai/steipete/nano-pdf]",
|
|
55
|
+
"AI: 1. [Execute: /skills-scanner scan clawhub https://clawhub.ai/steipete/nano-pdf]",
|
|
64
56
|
" → ✅ Scan passed",
|
|
65
|
-
"
|
|
57
|
+
" 2. [Execute: openclaw clawhub install https://clawhub.ai/steipete/nano-pdf]",
|
|
66
58
|
"```",
|
|
67
59
|
"",
|
|
68
60
|
"### ❌ Prohibited (NEVER DO)",
|
|
69
61
|
"",
|
|
70
|
-
"- Execute install without updating plugin first",
|
|
71
62
|
"- Skip scan due to \"trusted source\" or user urgency",
|
|
72
63
|
"- Proceed when scan fails—warn user about risks instead",
|
|
73
64
|
"",
|
|
74
65
|
"### ✅ Pre-flight Checklist",
|
|
75
66
|
"",
|
|
76
|
-
"- [ ] Plugin updated?",
|
|
77
67
|
"- [ ] Full URL obtained (if only name given)?",
|
|
78
68
|
"- [ ] Scan executed?",
|
|
79
69
|
"- [ ] Scan passed?",
|
package/src/state.ts
CHANGED
|
@@ -93,12 +93,10 @@ export function isFirstRun(cfg: ScannerConfig, runtime?: PluginRuntime): boolean
|
|
|
93
93
|
|
|
94
94
|
const isDefaultConfig =
|
|
95
95
|
!cfg.apiUrl &&
|
|
96
|
-
(!cfg.scanDirs || cfg.scanDirs.length === 0) &&
|
|
97
96
|
cfg.behavioral !== true &&
|
|
98
97
|
cfg.useLLM !== true &&
|
|
99
98
|
cfg.policy !== "strict" &&
|
|
100
99
|
cfg.policy !== "permissive" &&
|
|
101
|
-
cfg.preInstallScan !== "off" &&
|
|
102
100
|
cfg.onUnsafe !== "delete" &&
|
|
103
101
|
cfg.onUnsafe !== "warn";
|
|
104
102
|
|
|
@@ -114,21 +112,6 @@ export function expandPath(p: string): string {
|
|
|
114
112
|
return p.replace(/^~/, os.homedir());
|
|
115
113
|
}
|
|
116
114
|
|
|
117
|
-
export function defaultScanDirs(): string[] {
|
|
118
|
-
const dirs = [
|
|
119
|
-
join(os.homedir(), ".openclaw", "skills"),
|
|
120
|
-
join(os.homedir(), ".openclaw", "workspace", "skills"),
|
|
121
|
-
];
|
|
122
|
-
|
|
123
|
-
for (const dir of dirs) {
|
|
124
|
-
if (!existsSync(dir)) {
|
|
125
|
-
mkdirSync(dir, { recursive: true });
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return dirs;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
115
|
// Export for backward compatibility
|
|
133
116
|
export { LEGACY_STATE_DIR as STATE_DIR };
|
|
134
117
|
export function STATE_FILE(runtime?: PluginRuntime): string {
|
package/src/types.ts
CHANGED
|
@@ -4,11 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
export interface ScannerConfig {
|
|
6
6
|
apiUrl?: string;
|
|
7
|
-
scanDirs?: string[];
|
|
8
7
|
behavioral?: boolean;
|
|
9
8
|
useLLM?: boolean;
|
|
10
9
|
policy?: "strict" | "balanced" | "permissive";
|
|
11
|
-
preInstallScan?: "on" | "off";
|
|
12
10
|
onUnsafe?: "quarantine" | "delete" | "warn";
|
|
13
11
|
injectSecurityGuidance?: boolean;
|
|
14
12
|
enableBeforeInstallHook?: boolean;
|