opencode-api-security-testing 3.0.6 → 3.0.8
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/package.json +9 -3
- package/preuninstall.mjs +76 -0
- package/src/hooks/directory-agents-injector.ts +10 -6
- package/src/index.ts +18 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-api-security-testing",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.8",
|
|
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",
|
|
@@ -10,10 +10,12 @@
|
|
|
10
10
|
"core/",
|
|
11
11
|
"references/",
|
|
12
12
|
"SKILL.md",
|
|
13
|
-
"postinstall.mjs"
|
|
13
|
+
"postinstall.mjs",
|
|
14
|
+
"preuninstall.mjs"
|
|
14
15
|
],
|
|
15
16
|
"scripts": {
|
|
16
|
-
"postinstall": "node postinstall.mjs"
|
|
17
|
+
"postinstall": "node postinstall.mjs",
|
|
18
|
+
"preuninstall": "node preuninstall.mjs"
|
|
17
19
|
},
|
|
18
20
|
"keywords": [
|
|
19
21
|
"opencode",
|
|
@@ -37,5 +39,9 @@
|
|
|
37
39
|
"dependencies": {
|
|
38
40
|
"@opencode-ai/plugin": "^1.1.19",
|
|
39
41
|
"@opencode-ai/sdk": "^1.1.19"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^25.5.2",
|
|
45
|
+
"typescript": "^6.0.2"
|
|
40
46
|
}
|
|
41
47
|
}
|
package/preuninstall.mjs
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* preuninstall.mjs - API Security Testing Plugin Cleanup
|
|
5
|
+
*
|
|
6
|
+
* Removes:
|
|
7
|
+
* 1. agents from ~/.config/opencode/agents/
|
|
8
|
+
* 2. SKILL.md and references from ~/.config/opencode/skills/api-security-testing/
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { unlinkSync, existsSync, readdirSync, rmdirSync, rmSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = join(__filename, "..");
|
|
17
|
+
|
|
18
|
+
function getOpencodeBaseDir() {
|
|
19
|
+
const home = process.env.HOME || process.env.USERPROFILE || "/root";
|
|
20
|
+
return join(home, ".config", "opencode");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const AGENTS_TO_REMOVE = [
|
|
24
|
+
"api-cyber-supervisor.md",
|
|
25
|
+
"api-probing-miner.md",
|
|
26
|
+
"api-resource-specialist.md",
|
|
27
|
+
"api-vuln-verifier.md",
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
function main() {
|
|
31
|
+
const agentsTargetDir = join(getOpencodeBaseDir(), "agents");
|
|
32
|
+
const skillTargetDir = join(getOpencodeBaseDir(), "skills", "api-security-testing");
|
|
33
|
+
|
|
34
|
+
console.log("[api-security-testing] Cleaning up...");
|
|
35
|
+
console.log(` Home: ${getOpencodeBaseDir()}`);
|
|
36
|
+
|
|
37
|
+
let totalRemoved = 0;
|
|
38
|
+
let totalFailed = 0;
|
|
39
|
+
|
|
40
|
+
console.log("\n[1/2] Removing agents...");
|
|
41
|
+
for (const agent of AGENTS_TO_REMOVE) {
|
|
42
|
+
const agentPath = join(agentsTargetDir, agent);
|
|
43
|
+
try {
|
|
44
|
+
if (existsSync(agentPath)) {
|
|
45
|
+
unlinkSync(agentPath);
|
|
46
|
+
console.log(` ✓ ${agent}`);
|
|
47
|
+
totalRemoved++;
|
|
48
|
+
}
|
|
49
|
+
} catch (err) {
|
|
50
|
+
console.error(` ✗ ${agent}: ${err.message}`);
|
|
51
|
+
totalFailed++;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.log("\n[2/2] Removing skill files...");
|
|
56
|
+
try {
|
|
57
|
+
if (existsSync(skillTargetDir)) {
|
|
58
|
+
rmSync(skillTargetDir, { recursive: true, force: true });
|
|
59
|
+
console.log(` ✓ ${skillTargetDir}`);
|
|
60
|
+
totalRemoved++;
|
|
61
|
+
}
|
|
62
|
+
} catch (err) {
|
|
63
|
+
console.error(` ✗ ${skillTargetDir}: ${err.message}`);
|
|
64
|
+
totalFailed++;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
console.log(`\n========================================`);
|
|
68
|
+
if (totalFailed === 0) {
|
|
69
|
+
console.log(`✓ Removed ${totalRemoved} item(s)`);
|
|
70
|
+
console.log(`\nThanks for using api-security-testing!`);
|
|
71
|
+
} else {
|
|
72
|
+
console.log(`⚠ Removed ${totalRemoved}, failed ${totalFailed}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
main();
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
|
-
import { existsSync, readFileSync } from "
|
|
3
|
-
import { dirname, join, resolve } from "
|
|
2
|
+
import { existsSync, readFileSync } from "fs";
|
|
3
|
+
import { dirname, join, resolve } from "path";
|
|
4
4
|
|
|
5
5
|
const AGENTS_FILENAME = "AGENTS.md";
|
|
6
6
|
const AGENTS_DIR = ".config/opencode/agents";
|
|
7
7
|
|
|
8
|
+
function getHomeDir(): string {
|
|
9
|
+
return process.env.HOME || process.env.USERPROFILE || "/root";
|
|
10
|
+
}
|
|
11
|
+
|
|
8
12
|
export function createDirectoryAgentsInjectorHook(ctx: PluginInput) {
|
|
13
|
+
const injectedPaths = new Set<string>();
|
|
14
|
+
|
|
9
15
|
function resolveAgentsDir(): string | null {
|
|
10
|
-
const home =
|
|
11
|
-
if (!home) return null;
|
|
16
|
+
const home = getHomeDir();
|
|
12
17
|
return join(home, AGENTS_DIR);
|
|
13
18
|
}
|
|
14
19
|
|
|
15
20
|
function findAgentsMdUp(startDir: string, agentsDir: string): string | null {
|
|
21
|
+
const home = getHomeDir();
|
|
16
22
|
let current = startDir;
|
|
17
23
|
|
|
18
24
|
while (true) {
|
|
@@ -35,8 +41,6 @@ export function createDirectoryAgentsInjectorHook(ctx: PluginInput) {
|
|
|
35
41
|
return `api-sec-inject-${sessionID}`;
|
|
36
42
|
}
|
|
37
43
|
|
|
38
|
-
const injectedPaths = new Set<string>();
|
|
39
|
-
|
|
40
44
|
const toolExecuteAfter = async (
|
|
41
45
|
input: { tool: string; sessionID: string; callID: string },
|
|
42
46
|
output: { title: string; output: string; metadata: unknown }
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Plugin } from "@opencode-ai/plugin";
|
|
2
2
|
import { tool } from "@opencode-ai/plugin";
|
|
3
|
-
import { join } from "path";
|
|
3
|
+
import { join, dirname, resolve } from "path";
|
|
4
4
|
import { existsSync, readFileSync } from "fs";
|
|
5
5
|
|
|
6
6
|
const SKILL_DIR = "skills/api-security-testing";
|
|
@@ -54,6 +54,12 @@ To activate these agents, simply mention their name in your response (e.g., "@ap
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
async function execShell(ctx: unknown, cmd: string): Promise<string> {
|
|
58
|
+
const shell = ctx as { $: (strings: TemplateStringsArray, ...expr: unknown[]) => Promise<{ toString(): string }> };
|
|
59
|
+
const result = await shell.$`${cmd}`;
|
|
60
|
+
return result.toString();
|
|
61
|
+
}
|
|
62
|
+
|
|
57
63
|
const ApiSecurityTestingPlugin: Plugin = async (ctx) => {
|
|
58
64
|
console.log("[api-security-testing] Plugin loaded");
|
|
59
65
|
|
|
@@ -78,8 +84,7 @@ tester = DeepAPITesterV55(target='${args.target}', headless=True)
|
|
|
78
84
|
results = tester.run_test()
|
|
79
85
|
print(results)
|
|
80
86
|
"`;
|
|
81
|
-
|
|
82
|
-
return result.toString();
|
|
87
|
+
return await execShell(ctx, cmd);
|
|
83
88
|
},
|
|
84
89
|
}),
|
|
85
90
|
|
|
@@ -100,8 +105,7 @@ fuzzer = APIFuzzer('${args.endpoint}')
|
|
|
100
105
|
results = fuzzer.fuzz(method='${args.method || 'GET'}')
|
|
101
106
|
print(results)
|
|
102
107
|
"`;
|
|
103
|
-
|
|
104
|
-
return result.toString();
|
|
108
|
+
return await execShell(ctx, cmd);
|
|
105
109
|
},
|
|
106
110
|
}),
|
|
107
111
|
|
|
@@ -122,8 +126,7 @@ verifier = VulnVerifier()
|
|
|
122
126
|
result = verifier.verify('${args.vuln_type}', '${args.endpoint}')
|
|
123
127
|
print(result)
|
|
124
128
|
"`;
|
|
125
|
-
|
|
126
|
-
return result.toString();
|
|
129
|
+
return await execShell(ctx, cmd);
|
|
127
130
|
},
|
|
128
131
|
}),
|
|
129
132
|
|
|
@@ -145,8 +148,7 @@ print(f'发现 {len(endpoints)} 个端点:')
|
|
|
145
148
|
for ep in endpoints:
|
|
146
149
|
print(ep)
|
|
147
150
|
"`;
|
|
148
|
-
|
|
149
|
-
return result.toString();
|
|
151
|
+
return await execShell(ctx, cmd);
|
|
150
152
|
},
|
|
151
153
|
}),
|
|
152
154
|
|
|
@@ -166,8 +168,7 @@ parser = JSParser()
|
|
|
166
168
|
endpoints = parser.parse_file('${args.file_path}')
|
|
167
169
|
print(f'从 JS 发现 {len(endpoints)} 个端点')
|
|
168
170
|
"`;
|
|
169
|
-
|
|
170
|
-
return result.toString();
|
|
171
|
+
return await execShell(ctx, cmd);
|
|
171
172
|
},
|
|
172
173
|
}),
|
|
173
174
|
|
|
@@ -187,8 +188,7 @@ analyzer = SmartAnalyzer()
|
|
|
187
188
|
result = analyzer.graphql_test('${args.endpoint}')
|
|
188
189
|
print(result)
|
|
189
190
|
"`;
|
|
190
|
-
|
|
191
|
-
return result.toString();
|
|
191
|
+
return await execShell(ctx, cmd);
|
|
192
192
|
},
|
|
193
193
|
}),
|
|
194
194
|
|
|
@@ -208,8 +208,7 @@ tester = CloudStorageTester()
|
|
|
208
208
|
result = tester.full_test('${args.bucket_url}')
|
|
209
209
|
print(result)
|
|
210
210
|
"`;
|
|
211
|
-
|
|
212
|
-
return result.toString();
|
|
211
|
+
return await execShell(ctx, cmd);
|
|
213
212
|
},
|
|
214
213
|
}),
|
|
215
214
|
|
|
@@ -230,8 +229,7 @@ tester = IDORTester()
|
|
|
230
229
|
result = tester.test('${args.endpoint}', '${args.resource_id}')
|
|
231
230
|
print(result)
|
|
232
231
|
"`;
|
|
233
|
-
|
|
234
|
-
return result.toString();
|
|
232
|
+
return await execShell(ctx, cmd);
|
|
235
233
|
},
|
|
236
234
|
}),
|
|
237
235
|
|
|
@@ -252,8 +250,7 @@ tester = SQLiTester()
|
|
|
252
250
|
result = tester.test('${args.endpoint}', '${args.param}')
|
|
253
251
|
print(result)
|
|
254
252
|
"`;
|
|
255
|
-
|
|
256
|
-
return result.toString();
|
|
253
|
+
return await execShell(ctx, cmd);
|
|
257
254
|
},
|
|
258
255
|
}),
|
|
259
256
|
|
|
@@ -273,8 +270,7 @@ tester = AuthTester()
|
|
|
273
270
|
result = tester.test('${args.endpoint}')
|
|
274
271
|
print(result)
|
|
275
272
|
"`;
|
|
276
|
-
|
|
277
|
-
return result.toString();
|
|
273
|
+
return await execShell(ctx, cmd);
|
|
278
274
|
},
|
|
279
275
|
}),
|
|
280
276
|
},
|
|
@@ -344,9 +340,4 @@ print(result)
|
|
|
344
340
|
};
|
|
345
341
|
};
|
|
346
342
|
|
|
347
|
-
|
|
348
|
-
if (filePath.startsWith("/")) return filePath;
|
|
349
|
-
return join(process.cwd(), filePath);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
export default ApiSecurityTestingPlugin;
|
|
343
|
+
export default ApiSecurityTestingPlugin;
|