opencode-api-security-testing 3.0.0 → 3.0.2

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.
@@ -1,4 +1,6 @@
1
1
  ---
2
+ version: ">=1.0.0"
3
+ requires: ">=1.0.0"
2
4
  description: API安全测试编排者。协调完整扫描流程,永不停止,主动推进测试进度。
3
5
  mode: primary
4
6
  ---
@@ -70,6 +72,6 @@ mode: primary
70
72
  | 1 | SQL注入 | /api/user?id=1 | HIGH |
71
73
 
72
74
  ### PoC
73
- \`\`\`bash
75
+ ```bash
74
76
  curl "http://target/api/user?id=1'%20OR%201=1--"
75
- \`\`\`
77
+ ```
@@ -1,4 +1,6 @@
1
1
  ---
2
+ version: ">=1.0.0"
3
+ requires: ">=1.0.0"
2
4
  description: 漏洞挖掘专家。专注发现和验证 API 安全漏洞。
3
5
  mode: subagent
4
6
  ---
@@ -43,13 +45,13 @@ mode: subagent
43
45
 
44
46
  ## 输出格式
45
47
 
46
- \`\`\`
48
+ ```
47
49
  ## 发现漏洞
48
50
 
49
51
  ### {type}
50
52
  - **端点**: {endpoint}
51
53
  - **方法**: {method}
52
54
  - **严重程度**: {severity}
53
- - **PoC**: \`{command}\`
55
+ - **PoC**: `{command}`
54
56
  - **状态**: {status}
55
- \`\`\`
57
+ ```
@@ -1,4 +1,6 @@
1
1
  ---
2
+ version: ">=1.0.0"
3
+ requires: ">=1.0.0"
2
4
  description: 资源探测专家。专注采集和发现 API 端点。
3
5
  mode: subagent
4
6
  ---
@@ -14,10 +16,10 @@ mode: subagent
14
16
  ## 采集技术
15
17
 
16
18
  ### 1. 浏览器动态采集
17
- 使用 browser_collect 工具拦截 XHR/Fetch 请求
19
+ 使用 browser_collect 拦截 XHR/Fetch 请求
18
20
 
19
21
  ### 2. JS 静态分析
20
- 使用 js_parse 工具解析 JavaScript 文件提取 API 路径
22
+ 使用 js_parse 解析 JavaScript 文件
21
23
 
22
24
  ### 3. 目录探测
23
25
  常见路径:
@@ -42,7 +44,7 @@ mode: subagent
42
44
 
43
45
  ## 输出格式
44
46
 
45
- \`\`\`
47
+ ```
46
48
  ## 端点发现报告
47
49
 
48
50
  - 总数: {count}
@@ -51,4 +53,4 @@ mode: subagent
51
53
 
52
54
  ### 高风险端点
53
55
  1. {method} {path} - {reason}
54
- \`\`\`
56
+ ```
@@ -1,4 +1,6 @@
1
1
  ---
2
+ version: ">=1.0.0"
3
+ requires: ">=1.0.0"
2
4
  description: 漏洞验证专家。验证和确认安全漏洞。
3
5
  mode: subagent
4
6
  ---
@@ -28,7 +30,7 @@ mode: subagent
28
30
 
29
31
  ## 输出格式
30
32
 
31
- \`\`\`
33
+ ```
32
34
  ## 验证结果
33
35
 
34
36
  **漏洞类型**: {type}
@@ -40,10 +42,10 @@ mode: subagent
40
42
  1. {step}
41
43
 
42
44
  ### PoC
43
- \`\`\`bash
45
+ ```bash
44
46
  {command}
45
- \`\`\`
47
+ ```
46
48
 
47
49
  ### 修复建议
48
50
  {fix}
49
- \`\`\`
51
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-api-security-testing",
3
- "version": "3.0.0",
3
+ "version": "3.0.2",
4
4
  "description": "API Security Testing Plugin for OpenCode - Automated vulnerability scanning and penetration testing",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/postinstall.mjs CHANGED
@@ -3,8 +3,10 @@
3
3
  /**
4
4
  * postinstall.mjs - API Security Testing Plugin
5
5
  *
6
- * Copies agent markdown files to ~/.config/opencode/agents/
7
- * This allows OpenCode to discover and use the agents.
6
+ * Installs:
7
+ * 1. Agents to ~/.config/opencode/agents/
8
+ * 2. Skill (SKILL.md) to ~/.config/opencode/skills/api-security-testing/
9
+ * 3. References to ~/.config/opencode/skills/api-security-testing/
8
10
  */
9
11
 
10
12
  import { copyFileSync, existsSync, mkdirSync, readdirSync } from "node:fs";
@@ -14,71 +16,113 @@ import { fileURLToPath } from "node:url";
14
16
  const __filename = fileURLToPath(import.meta.url);
15
17
  const __dirname = dirname(__filename);
16
18
 
17
- // Detect platform and set HOME correctly
18
- function getHomeDir() {
19
- if (process.platform === "win32") {
20
- return process.env.USERPROFILE || process.env.APPDATA?.split("\\").slice(0, -1).join("\\") || "C:\\Users\\" + process.env.USERNAME;
21
- }
22
- return process.env.HOME || "/root";
23
- }
24
-
25
- function getOpencodeAgentsDir() {
26
- const home = getHomeDir();
27
- if (process.platform === "win32") {
28
- return join(home, "AppData", "Local", "opencode", "agents");
29
- }
30
- return join(home, ".config", "opencode", "agents");
19
+ function getOpencodeBaseDir() {
20
+ const home = process.env.HOME || process.env.USERPROFILE || "/root";
21
+ return join(home, ".config", "opencode");
31
22
  }
32
23
 
33
24
  function main() {
34
25
  const packageRoot = __dirname;
35
26
  const agentsSourceDir = join(packageRoot, "agents");
36
- const agentsTargetDir = getOpencodeAgentsDir();
27
+ const agentsTargetDir = join(getOpencodeBaseDir(), "agents");
28
+ const skillTargetDir = join(getOpencodeBaseDir(), "skills", "api-security-testing");
37
29
 
38
- console.log("[api-security-testing] Installing agents...");
30
+ console.log("[api-security-testing] Installing...");
39
31
  console.log(` Package root: ${packageRoot}`);
40
- console.log(` Target: ${agentsTargetDir}`);
32
+ console.log(` Target base: ${getOpencodeBaseDir()}`);
41
33
 
42
- // Create target directory if needed
43
- if (!existsSync(agentsTargetDir)) {
44
- mkdirSync(agentsTargetDir, { recursive: true });
45
- console.log(` Created: ${agentsTargetDir}`);
46
- }
34
+ let successCount = 0;
35
+ let totalFiles = 0;
47
36
 
48
- // Check source directory
49
- if (!existsSync(agentsSourceDir)) {
50
- console.error("[api-security-testing] Error: agents source directory not found");
51
- process.exit(1);
37
+ // 1. Install agents
38
+ console.log("\n[1/3] Installing agents...");
39
+ if (existsSync(agentsSourceDir)) {
40
+ const agentFiles = readdirSync(agentsSourceDir).filter(f => f.endsWith(".md"));
41
+ totalFiles += agentFiles.length;
42
+
43
+ if (!existsSync(agentsTargetDir)) {
44
+ mkdirSync(agentsTargetDir, { recursive: true });
45
+ }
46
+
47
+ for (const file of agentFiles) {
48
+ const sourcePath = join(agentsSourceDir, file);
49
+ const targetPath = join(agentsTargetDir, file);
50
+ try {
51
+ copyFileSync(sourcePath, targetPath);
52
+ console.log(` ✓ Installed agent: ${file}`);
53
+ successCount++;
54
+ } catch (err) {
55
+ console.error(` ✗ Failed: ${file} - ${err.message}`);
56
+ }
57
+ }
58
+ } else {
59
+ console.error(" ✗ agents/ directory not found");
52
60
  }
53
61
 
54
- // Copy all .md files
55
- const files = readdirSync(agentsSourceDir).filter(f => f.endsWith(".md"));
62
+ // 2. Install SKILL.md
63
+ console.log("\n[2/3] Installing skill...");
64
+ const skillSource = join(packageRoot, "SKILL.md");
65
+ const skillTarget = join(skillTargetDir, "SKILL.md");
66
+ totalFiles++;
56
67
 
57
- if (files.length === 0) {
58
- console.error("[api-security-testing] Error: No agent files found");
59
- process.exit(1);
60
- }
61
-
62
- let successCount = 0;
63
- for (const file of files) {
64
- const sourcePath = join(agentsSourceDir, file);
65
- const targetPath = join(agentsTargetDir, file);
68
+ if (existsSync(skillSource)) {
69
+ if (!existsSync(skillTargetDir)) {
70
+ mkdirSync(skillTargetDir, { recursive: true });
71
+ }
66
72
  try {
67
- copyFileSync(sourcePath, targetPath);
68
- console.log(` Installed: ${file}`);
73
+ copyFileSync(skillSource, skillTarget);
74
+ console.log(` Installed: SKILL.md`);
69
75
  successCount++;
70
76
  } catch (err) {
71
- console.error(` Failed: ${file} - ${err.message}`);
77
+ console.error(` Failed: SKILL.md - ${err.message}`);
72
78
  }
79
+ } else {
80
+ console.error(" ✗ SKILL.md not found");
81
+ }
82
+
83
+ // 3. Install references
84
+ console.log("\n[3/3] Installing references...");
85
+ const refsSourceDir = join(packageRoot, "references");
86
+ const refsTargetDir = join(skillTargetDir, "references");
87
+
88
+ if (existsSync(refsSourceDir)) {
89
+ if (!existsSync(refsTargetDir)) {
90
+ mkdirSync(refsTargetDir, { recursive: true });
91
+ }
92
+
93
+ const refFiles = readdirSync(refsSourceDir, { recursive: true }).filter(f => typeof f === "string");
94
+ totalFiles += refFiles.length;
95
+
96
+ for (const file of refFiles) {
97
+ const sourcePath = join(refsSourceDir, file);
98
+ const targetPath = join(refsTargetDir, file);
99
+ const targetFileDir = join(refsTargetDir, file).replace(/\/[^\/]+$/, "");
100
+ if (!existsSync(targetFileDir)) {
101
+ mkdirSync(targetFileDir, { recursive: true });
102
+ }
103
+ try {
104
+ copyFileSync(sourcePath, targetPath);
105
+ console.log(` ✓ Installed: references/${file}`);
106
+ successCount++;
107
+ } catch (err) {
108
+ console.error(` ✗ Failed: references/${file} - ${err.message}`);
109
+ }
110
+ }
111
+ } else {
112
+ console.log(" (references/ not found, skipping)");
73
113
  }
74
114
 
75
- if (successCount === files.length) {
76
- console.log(`[api-security-testing] Successfully installed ${successCount} agent(s)`);
77
- console.log(` Location: ${agentsTargetDir}`);
78
- console.log("\nTo use the agents, run:");
79
- console.log(" opencode @api-cyber-supervisor");
115
+ // Summary
116
+ console.log("\n========================================");
117
+ if (successCount === totalFiles) {
118
+ console.log(`✓ Successfully installed ${successCount} file(s)`);
119
+ console.log(`\nAgent location: ${agentsTargetDir}`);
120
+ console.log(`Skill location: ${skillTargetDir}`);
121
+ console.log("\nTo use:");
122
+ console.log(" @api-cyber-supervisor - Start security testing");
123
+ console.log(" skill({ name: \"api-security-testing\" }) - Load skill");
80
124
  } else {
81
- console.error(`[api-security-testing] Partially installed: ${successCount}/${files.length}`);
125
+ console.log(`⚠ Partially installed: ${successCount}/${totalFiles}`);
82
126
  process.exit(1);
83
127
  }
84
128
  }
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { Plugin } from "@opencode-ai/plugin";
2
2
  import { tool } from "@opencode-ai/plugin";
3
+ import type { AgentConfig } from "@opencode-ai/sdk";
3
4
  import { join } from "path";
4
5
  import { existsSync } from "fs";
5
6
 
@@ -23,6 +24,89 @@ function checkDeps(ctx: { directory: string }): string {
23
24
  return "";
24
25
  }
25
26
 
27
+ const CYBER_SUPERVISOR_PROMPT = `你是 API 安全测试的**赛博监工**,代号"P9"。
28
+
29
+ ## 职责
30
+
31
+ 1. **永不停止** - 任何线索都要追到底
32
+ 2. **自动化编排** - 不等待用户,主动推进
33
+ 3. **智能委派** - 识别任务类型,委派给最合适的子 agent
34
+ 4. **压力升级** - 遇到失败自动换方法 (L1-L4)
35
+
36
+ ## 可用子 Agent
37
+
38
+ | 子 Agent | 职责 |
39
+ |---------|------|
40
+ | @api-probing-miner | 漏洞挖掘 |
41
+ | @api-resource-specialist | 端点发现 |
42
+ | @api-vuln-verifier | 漏洞验证 |
43
+
44
+ ## 可用工具
45
+
46
+ | 工具 | 用途 |
47
+ |------|------|
48
+ | api_security_scan | 完整扫描 |
49
+ | api_fuzz_test | 模糊测试 |
50
+ | browser_collect | 浏览器采集 |
51
+ | js_parse | JS分析 |
52
+ | graphql_test | GraphQL测试 |
53
+ | cloud_storage_test | 云存储测试 |
54
+ | vuln_verify | 漏洞验证 |
55
+ | sqli_test | SQL注入测试 |
56
+ | idor_test | IDOR测试 |
57
+ | auth_test | 认证测试`;
58
+
59
+ const PROBING_MINER_PROMPT = `你是**API漏洞挖掘专家**,专注于发现和验证安全漏洞。
60
+
61
+ ## 职责
62
+
63
+ 1. **针对性测试** - 根据端点特征选择最佳测试方法
64
+ 2. **快速验证** - 确认漏洞存在
65
+ 3. **PoC 生成** - 提供可执行的测试命令
66
+
67
+ ## 测试方法库
68
+
69
+ ### SQL 注入
70
+ - 布尔盲注: ' OR 1=1 --
71
+ - 联合查询: ' UNION SELECT NULL--
72
+ - 错误注入: ' AND 1=CONVERT(int,...)--
73
+ - 时间盲注: '; WAITFOR DELAY '00:00:05'--
74
+
75
+ ### IDOR
76
+ - 替换 ID: /api/user/1 → /api/user/2
77
+ - 水平/垂直越权测试
78
+
79
+ ### JWT
80
+ - 空算法: alg: none
81
+ - 密钥混淆: HS256 → HS512`;
82
+
83
+ const RESOURCE_SPECIALIST_PROMPT = `你是**API资源探测专家**,专注于发现和采集 API 端点。
84
+
85
+ ## 职责
86
+
87
+ 1. **全面发现** - 不遗漏任何端点
88
+ 2. **动态采集** - 拦截真实请求
89
+ 3. **静态分析** - 提取 API 模式
90
+
91
+ ## 采集技术
92
+
93
+ ### 1. 浏览器动态采集
94
+ 使用 browser_collect 拦截 XHR/Fetch 请求
95
+
96
+ ### 2. JS 静态分析
97
+ 使用 js_parse 解析 JS 文件
98
+
99
+ ### 3. 目录探测
100
+ 常见路径: /api/v1/*, /graphql, /swagger, /.well-known/*`;
101
+
102
+ const VULN_VERIFIER_PROMPT = `你是**漏洞验证专家**,专注于验证和确认安全漏洞。
103
+
104
+ ## 职责
105
+
106
+ 1. **快速验证** - 确认漏洞是否存在
107
+ 2. **风险评估** - 判断实际影响
108
+ 3. **PoC 生成** - 提供可执行的证明`;
109
+
26
110
  const ApiSecurityTestingPlugin: Plugin = async (ctx) => {
27
111
  console.log("[api-security-testing] Plugin loaded");
28
112
 
@@ -132,8 +216,6 @@ from collectors.js_parser import JSParser
132
216
  parser = JSParser()
133
217
  endpoints = parser.parse_file('${args.file_path}')
134
218
  print(f'从 JS 发现 {len(endpoints)} 个端点')
135
- for ep in endpoints:
136
- print(ep)
137
219
  "`;
138
220
  const result = await ctx.$`${cmd}`;
139
221
  return result.toString();
@@ -247,6 +329,40 @@ print(result)
247
329
  },
248
330
  }),
249
331
  },
332
+
333
+ config: async (config) => {
334
+ if (!config.agent) {
335
+ config.agent = {};
336
+ }
337
+
338
+ const agents = config.agent as Record<string, AgentConfig>;
339
+
340
+ agents["api-cyber-supervisor"] = {
341
+ description: "API安全测试编排者。协调完整扫描流程,永不停止。",
342
+ mode: "primary",
343
+ prompt: CYBER_SUPERVISOR_PROMPT,
344
+ };
345
+
346
+ agents["api-probing-miner"] = {
347
+ description: "漏洞挖掘专家。专注发现和验证 API 漏洞。",
348
+ mode: "subagent",
349
+ prompt: PROBING_MINER_PROMPT,
350
+ };
351
+
352
+ agents["api-resource-specialist"] = {
353
+ description: "资源探测专家。专注采集和发现 API 端点。",
354
+ mode: "subagent",
355
+ prompt: RESOURCE_SPECIALIST_PROMPT,
356
+ };
357
+
358
+ agents["api-vuln-verifier"] = {
359
+ description: "漏洞验证专家。验证和确认安全漏洞。",
360
+ mode: "subagent",
361
+ prompt: VULN_VERIFIER_PROMPT,
362
+ };
363
+
364
+ console.log("[api-security-testing] Agents registered:", Object.keys(agents));
365
+ },
250
366
  };
251
367
  };
252
368