cyberaudit-skill 3.1.4 → 3.2.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/README.md +84 -25
- package/dist/cli.d.ts +10 -0
- package/dist/cli.js +555 -170
- package/dist/cli.test.d.ts +1 -0
- package/dist/cli.test.js +100 -0
- package/dist/mcp-server.d.ts +135 -1
- package/dist/mcp-server.js +185 -96
- package/dist/mcp-server.test.d.ts +1 -0
- package/dist/mcp-server.test.js +77 -0
- package/dist/report/generator.d.ts +2 -0
- package/dist/report/generator.js +260 -0
- package/dist/report/generator.test.d.ts +1 -0
- package/dist/report/generator.test.js +73 -0
- package/dist/report/types.d.ts +31 -0
- package/dist/report/types.js +1 -0
- package/dist/scanners/secrets.d.ts +32 -0
- package/dist/scanners/secrets.js +437 -0
- package/dist/scanners/secrets.test.d.ts +1 -0
- package/dist/scanners/secrets.test.js +96 -0
- package/dist/scanners/types.d.ts +22 -0
- package/dist/scanners/types.js +1 -0
- package/dist/scanners/web.d.ts +37 -0
- package/dist/scanners/web.js +327 -0
- package/dist/scanners/web.test.d.ts +1 -0
- package/dist/scanners/web.test.js +67 -0
- package/package.json +15 -3
- package/skills/cyberaudit/AGENT-BOOT.md +1 -1
- package/skills/cyberaudit/COMMANDS.md +11 -1
- package/skills/cyberaudit/INSTALL.md +7 -6
- package/skills/cyberaudit/README.md +20 -5
- package/skills/cyberaudit/SKILL.md +20 -5
- package/skills/cyberaudit/cloud/CLOUD-CHECKLIST.md +85 -0
- package/skills/cyberaudit/cloud/CLOUD-PHILOSOPHY.md +91 -0
- package/skills/cyberaudit/cloud/CLOUD-REMEDIATION-LIBRARY.md +145 -0
- package/skills/cyberaudit/commands/audit-angular.md +11 -0
- package/skills/cyberaudit/commands/audit-api-bola.md +11 -0
- package/skills/cyberaudit/commands/audit-api-bopla.md +11 -0
- package/skills/cyberaudit/commands/audit-api-graphql.md +11 -0
- package/skills/cyberaudit/commands/audit-api-inventory.md +11 -0
- package/skills/cyberaudit/commands/audit-api-rate-limit.md +11 -0
- package/skills/cyberaudit/commands/audit-api-rest.md +11 -0
- package/skills/cyberaudit/commands/audit-api-third-party.md +11 -0
- package/skills/cyberaudit/commands/audit-api-ws.md +11 -0
- package/skills/cyberaudit/commands/audit-auth-api.md +11 -0
- package/skills/cyberaudit/commands/audit-auth-mobile.md +11 -0
- package/skills/cyberaudit/commands/audit-auth.md +12 -0
- package/skills/cyberaudit/commands/audit-binary.md +11 -0
- package/skills/cyberaudit/commands/audit-cis.md +11 -0
- package/skills/cyberaudit/commands/audit-cloud-iam.md +11 -0
- package/skills/cyberaudit/commands/audit-cloud-network.md +11 -0
- package/skills/cyberaudit/commands/audit-cloud-s3.md +11 -0
- package/skills/cyberaudit/commands/audit-cloud.md +10 -0
- package/skills/cyberaudit/commands/audit-cors.md +11 -0
- package/skills/cyberaudit/commands/audit-crypto-mobile.md +11 -0
- package/skills/cyberaudit/commands/audit-crypto.md +10 -0
- package/skills/cyberaudit/commands/audit-csrf.md +11 -0
- package/skills/cyberaudit/commands/audit-deeplinks.md +11 -0
- package/skills/cyberaudit/commands/audit-deps.md +11 -0
- package/skills/cyberaudit/commands/audit-deserial.md +11 -0
- package/skills/cyberaudit/commands/audit-exec.md +11 -0
- package/skills/cyberaudit/commands/audit-expo.md +11 -0
- package/skills/cyberaudit/commands/audit-express.md +11 -0
- package/skills/cyberaudit/commands/audit-flutter.md +11 -0
- package/skills/cyberaudit/commands/audit-headers.md +11 -0
- package/skills/cyberaudit/commands/audit-hipaa.md +11 -0
- package/skills/cyberaudit/commands/audit-idor.md +11 -0
- package/skills/cyberaudit/commands/audit-injection.md +12 -0
- package/skills/cyberaudit/commands/audit-ionic.md +11 -0
- package/skills/cyberaudit/commands/audit-laravel.md +11 -0
- package/skills/cyberaudit/commands/audit-logic.md +11 -0
- package/skills/cyberaudit/commands/audit-masvs.md +11 -0
- package/skills/cyberaudit/commands/audit-nestjs.md +11 -0
- package/skills/cyberaudit/commands/audit-network.md +11 -0
- package/skills/cyberaudit/commands/audit-nextjs.md +11 -0
- package/skills/cyberaudit/commands/audit-owasp.md +11 -0
- package/skills/cyberaudit/commands/audit-pci.md +11 -0
- package/skills/cyberaudit/commands/audit-permissions.md +11 -0
- package/skills/cyberaudit/commands/audit-react-native.md +11 -0
- package/skills/cyberaudit/commands/audit-react.md +11 -0
- package/skills/cyberaudit/commands/audit-rgpd.md +11 -0
- package/skills/cyberaudit/commands/audit-runtime.md +11 -0
- package/skills/cyberaudit/commands/audit-secrets.md +11 -0
- package/skills/cyberaudit/commands/audit-ssrf.md +11 -0
- package/skills/cyberaudit/commands/audit-storage.md +11 -0
- package/skills/cyberaudit/commands/audit-vue.md +11 -0
- package/skills/cyberaudit/commands/audit-xss.md +11 -0
- package/skills/cyberaudit/commands/audit-xxe.md +11 -0
- package/skills/cyberaudit/reports/EXECUTIVE-SUMMARY-TEMPLATE.md +1 -1
- package/skills/cyberaudit/reports/REPORT-TEMPLATE-CLOUD.md +103 -0
- package/skills/cyberaudit/reports/REPORT-TEMPLATE-MOBILE.md +2 -2
- package/skills/cyberaudit/reports/REPORT-TEMPLATE-WEB.md +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/cli.test.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { existsSync, rmSync, readFileSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { tmpdir } from 'os';
|
|
5
|
+
import { mkdtempSync } from 'fs';
|
|
6
|
+
describe('CLI Installer Safety', () => {
|
|
7
|
+
let tmp;
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
tmp = mkdtempSync(join(tmpdir(), 'cyberaudit-test-'));
|
|
10
|
+
});
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
13
|
+
});
|
|
14
|
+
it('isSafePath should block paths outside HOME containing cyberaudit', async () => {
|
|
15
|
+
const cliPath = join(process.cwd(), 'src', 'cli.ts');
|
|
16
|
+
const content = readFileSync(cliPath, 'utf-8');
|
|
17
|
+
// New version uses isSafeInsideHome, isSafeSkillPath, isSafeCommandPath
|
|
18
|
+
expect(content).toMatch(/isSafe.*Path/);
|
|
19
|
+
expect(content).toContain('homedir');
|
|
20
|
+
expect(content).toContain('cyberaudit');
|
|
21
|
+
expect(content).toContain('isSafeInsideHome');
|
|
22
|
+
});
|
|
23
|
+
it('installDir should exist as function', () => {
|
|
24
|
+
const content = readFileSync(join(process.cwd(), 'src', 'cli.ts'), 'utf-8');
|
|
25
|
+
expect(content).toContain('function installDir');
|
|
26
|
+
});
|
|
27
|
+
it('installForCursor handles corrupted mcp.json with backup', () => {
|
|
28
|
+
const cliContent = readFileSync(join(process.cwd(), 'src/cli.ts'), 'utf-8');
|
|
29
|
+
expect(cliContent).toContain('mcp.json is corrupted');
|
|
30
|
+
expect(cliContent).toContain('.bak');
|
|
31
|
+
expect(cliContent).toContain('copyFileSync');
|
|
32
|
+
});
|
|
33
|
+
it('version comes from package.json not hardcoded', () => {
|
|
34
|
+
const cliContent = readFileSync(join(process.cwd(), 'src/cli.ts'), 'utf-8');
|
|
35
|
+
expect(cliContent).toContain('PKG.version');
|
|
36
|
+
expect(cliContent).not.toMatch(/version:\s*\"3\.0\.0\"/);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe('Command files completeness', () => {
|
|
40
|
+
it('should have at least 50 command files', () => {
|
|
41
|
+
const fs = require('fs');
|
|
42
|
+
const files = fs.readdirSync(join(process.cwd(), 'skills', 'cyberaudit', 'commands'));
|
|
43
|
+
expect(files.length).toBeGreaterThanOrEqual(50);
|
|
44
|
+
});
|
|
45
|
+
it('should have audit-cloud file', () => {
|
|
46
|
+
const fs = require('fs');
|
|
47
|
+
const files = fs.readdirSync(join(process.cwd(), 'skills', 'cyberaudit', 'commands'));
|
|
48
|
+
expect(files).toContain('audit-cloud.md');
|
|
49
|
+
expect(files).toContain('audit-cloud-s3.md');
|
|
50
|
+
expect(files).toContain('audit-cloud-iam.md');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe('Cloud module completeness', () => {
|
|
54
|
+
it('cloud checklist exists', () => {
|
|
55
|
+
expect(existsSync(join(process.cwd(), 'skills', 'cyberaudit', 'cloud', 'CLOUD-CHECKLIST.md'))).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
it('cloud philosophy exists', () => {
|
|
58
|
+
expect(existsSync(join(process.cwd(), 'skills', 'cyberaudit', 'cloud', 'CLOUD-PHILOSOPHY.md'))).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
it('cloud remediation exists', () => {
|
|
61
|
+
expect(existsSync(join(process.cwd(), 'skills', 'cyberaudit', 'cloud', 'CLOUD-REMEDIATION-LIBRARY.md'))).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
it('cloud report template exists', () => {
|
|
64
|
+
expect(existsSync(join(process.cwd(), 'skills', 'cyberaudit', 'reports', 'REPORT-TEMPLATE-CLOUD.md'))).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe('Multi-agent support (like ui-ux-pro)', () => {
|
|
68
|
+
it('should support at least 15 agents', () => {
|
|
69
|
+
const content = readFileSync(join(process.cwd(), 'src', 'cli.ts'), 'utf-8');
|
|
70
|
+
// Count Agent union type entries
|
|
71
|
+
const match = content.match(/type Agent =([\s\S]*?);/);
|
|
72
|
+
expect(match).toBeTruthy();
|
|
73
|
+
const agents = match[1].split('|').map(s => s.trim()).filter(Boolean);
|
|
74
|
+
expect(agents.length).toBeGreaterThanOrEqual(15);
|
|
75
|
+
});
|
|
76
|
+
it('should have MAIN_COMMANDS 8 for \"/\" menu', () => {
|
|
77
|
+
const content = readFileSync(join(process.cwd(), 'src', 'cli.ts'), 'utf-8');
|
|
78
|
+
expect(content).toContain('MAIN_COMMANDS');
|
|
79
|
+
// Should contain 8 entries
|
|
80
|
+
const mainMatch = content.match(/const MAIN_COMMANDS = \[([\s\S]*?)\];/);
|
|
81
|
+
expect(mainMatch).toBeTruthy();
|
|
82
|
+
const count = (mainMatch[1].match(/\.md/g) || []).length;
|
|
83
|
+
expect(count).toBe(8);
|
|
84
|
+
});
|
|
85
|
+
it('should define AGENT_CONFIG for many agents', () => {
|
|
86
|
+
const content = readFileSync(join(process.cwd(), 'src', 'cli.ts'), 'utf-8');
|
|
87
|
+
expect(content).toContain('AGENT_CONFIG');
|
|
88
|
+
expect(content).toContain('claude-code');
|
|
89
|
+
expect(content).toContain('cursor');
|
|
90
|
+
expect(content).toContain('windsurf');
|
|
91
|
+
expect(content).toContain('copilot');
|
|
92
|
+
expect(content).toContain('codex');
|
|
93
|
+
expect(content).toContain('continue');
|
|
94
|
+
});
|
|
95
|
+
it('should install commands for \"/\" menu', () => {
|
|
96
|
+
const content = readFileSync(join(process.cwd(), 'src', 'cli.ts'), 'utf-8');
|
|
97
|
+
expect(content).toContain('installCommands');
|
|
98
|
+
expect(content).toContain('"/" will show');
|
|
99
|
+
});
|
|
100
|
+
});
|
package/dist/mcp-server.d.ts
CHANGED
|
@@ -1,2 +1,136 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
export {
|
|
2
|
+
export declare const MCP_TOOLS: ({
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: string;
|
|
7
|
+
properties: {
|
|
8
|
+
target: {
|
|
9
|
+
type: string;
|
|
10
|
+
description: string;
|
|
11
|
+
};
|
|
12
|
+
depth: {
|
|
13
|
+
type: string;
|
|
14
|
+
enum: string[];
|
|
15
|
+
default: string;
|
|
16
|
+
};
|
|
17
|
+
platform?: undefined;
|
|
18
|
+
};
|
|
19
|
+
required: string[];
|
|
20
|
+
};
|
|
21
|
+
} | {
|
|
22
|
+
name: string;
|
|
23
|
+
description: string;
|
|
24
|
+
inputSchema: {
|
|
25
|
+
type: string;
|
|
26
|
+
properties: {
|
|
27
|
+
target: {
|
|
28
|
+
type: string;
|
|
29
|
+
description: string;
|
|
30
|
+
};
|
|
31
|
+
platform: {
|
|
32
|
+
type: string;
|
|
33
|
+
enum: string[];
|
|
34
|
+
default: string;
|
|
35
|
+
};
|
|
36
|
+
depth?: undefined;
|
|
37
|
+
};
|
|
38
|
+
required: string[];
|
|
39
|
+
};
|
|
40
|
+
} | {
|
|
41
|
+
name: string;
|
|
42
|
+
description: string;
|
|
43
|
+
inputSchema: {
|
|
44
|
+
type: string;
|
|
45
|
+
properties: {
|
|
46
|
+
target: {
|
|
47
|
+
type: string;
|
|
48
|
+
description: string;
|
|
49
|
+
};
|
|
50
|
+
depth?: undefined;
|
|
51
|
+
platform?: undefined;
|
|
52
|
+
};
|
|
53
|
+
required: string[];
|
|
54
|
+
};
|
|
55
|
+
} | {
|
|
56
|
+
name: string;
|
|
57
|
+
description: string;
|
|
58
|
+
inputSchema: {
|
|
59
|
+
type: string;
|
|
60
|
+
properties: {
|
|
61
|
+
target?: undefined;
|
|
62
|
+
depth?: undefined;
|
|
63
|
+
platform?: undefined;
|
|
64
|
+
};
|
|
65
|
+
required?: undefined;
|
|
66
|
+
};
|
|
67
|
+
})[];
|
|
68
|
+
export declare const capabilities: {
|
|
69
|
+
tools: ({
|
|
70
|
+
name: string;
|
|
71
|
+
description: string;
|
|
72
|
+
inputSchema: {
|
|
73
|
+
type: string;
|
|
74
|
+
properties: {
|
|
75
|
+
target: {
|
|
76
|
+
type: string;
|
|
77
|
+
description: string;
|
|
78
|
+
};
|
|
79
|
+
depth: {
|
|
80
|
+
type: string;
|
|
81
|
+
enum: string[];
|
|
82
|
+
default: string;
|
|
83
|
+
};
|
|
84
|
+
platform?: undefined;
|
|
85
|
+
};
|
|
86
|
+
required: string[];
|
|
87
|
+
};
|
|
88
|
+
} | {
|
|
89
|
+
name: string;
|
|
90
|
+
description: string;
|
|
91
|
+
inputSchema: {
|
|
92
|
+
type: string;
|
|
93
|
+
properties: {
|
|
94
|
+
target: {
|
|
95
|
+
type: string;
|
|
96
|
+
description: string;
|
|
97
|
+
};
|
|
98
|
+
platform: {
|
|
99
|
+
type: string;
|
|
100
|
+
enum: string[];
|
|
101
|
+
default: string;
|
|
102
|
+
};
|
|
103
|
+
depth?: undefined;
|
|
104
|
+
};
|
|
105
|
+
required: string[];
|
|
106
|
+
};
|
|
107
|
+
} | {
|
|
108
|
+
name: string;
|
|
109
|
+
description: string;
|
|
110
|
+
inputSchema: {
|
|
111
|
+
type: string;
|
|
112
|
+
properties: {
|
|
113
|
+
target: {
|
|
114
|
+
type: string;
|
|
115
|
+
description: string;
|
|
116
|
+
};
|
|
117
|
+
depth?: undefined;
|
|
118
|
+
platform?: undefined;
|
|
119
|
+
};
|
|
120
|
+
required: string[];
|
|
121
|
+
};
|
|
122
|
+
} | {
|
|
123
|
+
name: string;
|
|
124
|
+
description: string;
|
|
125
|
+
inputSchema: {
|
|
126
|
+
type: string;
|
|
127
|
+
properties: {
|
|
128
|
+
target?: undefined;
|
|
129
|
+
depth?: undefined;
|
|
130
|
+
platform?: undefined;
|
|
131
|
+
};
|
|
132
|
+
required?: undefined;
|
|
133
|
+
};
|
|
134
|
+
})[];
|
|
135
|
+
};
|
|
136
|
+
export declare function startMcpServer(): void;
|
package/dist/mcp-server.js
CHANGED
|
@@ -1,126 +1,215 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createInterface } from "readline";
|
|
3
|
-
import {
|
|
3
|
+
import { readFileSync, existsSync, statSync } from "fs";
|
|
4
|
+
import { join, dirname, resolve } from "path";
|
|
4
5
|
import { fileURLToPath } from "url";
|
|
6
|
+
import { scanSecrets, formatFindingsText } from "./scanners/secrets.js";
|
|
7
|
+
import { scanWeb, formatWebFindingsText } from "./scanners/web.js";
|
|
5
8
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
const PKG_ROOT = join(__dirname, "..");
|
|
10
|
+
const SKILL_DIR = join(PKG_ROOT, "skills", "cyberaudit");
|
|
11
|
+
function getVersion() {
|
|
12
|
+
try {
|
|
13
|
+
const pkgPath = join(PKG_ROOT, "package.json");
|
|
14
|
+
if (existsSync(pkgPath)) {
|
|
15
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
16
|
+
return pkg.version || "3.1.5";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch { }
|
|
20
|
+
return "3.1.5";
|
|
21
|
+
}
|
|
22
|
+
const VERSION = getVersion();
|
|
23
|
+
export const MCP_TOOLS = [
|
|
24
|
+
{
|
|
25
|
+
name: "cyberaudit-web",
|
|
26
|
+
description: "Run a web application security audit (OWASP Top 10)",
|
|
27
|
+
inputSchema: {
|
|
28
|
+
type: "object",
|
|
29
|
+
properties: {
|
|
30
|
+
target: { type: "string", description: "URL, domain, or project path to audit" },
|
|
31
|
+
depth: { type: "string", enum: ["quick", "standard", "deep"], default: "standard" },
|
|
19
32
|
},
|
|
33
|
+
required: ["target"],
|
|
20
34
|
},
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
},
|
|
30
|
-
required: ["target"],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "cyberaudit-mobile",
|
|
38
|
+
description: "Run a mobile application security audit (OWASP MASVS)",
|
|
39
|
+
inputSchema: {
|
|
40
|
+
type: "object",
|
|
41
|
+
properties: {
|
|
42
|
+
target: { type: "string", description: "App identifier, APK/IPA path, or project path" },
|
|
43
|
+
platform: { type: "string", enum: ["android", "ios", "both"], default: "both" },
|
|
31
44
|
},
|
|
45
|
+
required: ["target"],
|
|
32
46
|
},
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
},
|
|
41
|
-
required: ["target"],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "cyberaudit-api",
|
|
50
|
+
description: "Run an API security audit (OWASP API Top 10)",
|
|
51
|
+
inputSchema: {
|
|
52
|
+
type: "object",
|
|
53
|
+
properties: {
|
|
54
|
+
target: { type: "string", description: "API base URL, OpenAPI spec path, or project directory" },
|
|
42
55
|
},
|
|
56
|
+
required: ["target"],
|
|
43
57
|
},
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
},
|
|
52
|
-
required: ["target"],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "cyberaudit-cloud",
|
|
61
|
+
description: "Run a cloud configuration security audit (AWS/GCP/Azure S3, IAM, SG, storage)",
|
|
62
|
+
inputSchema: {
|
|
63
|
+
type: "object",
|
|
64
|
+
properties: {
|
|
65
|
+
target: { type: "string", description: "Cloud provider, IaC path (terraform/cloudformation), or config file path" },
|
|
53
66
|
},
|
|
67
|
+
required: ["target"],
|
|
54
68
|
},
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
},
|
|
63
|
-
required: ["target"],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: "cyberaudit-quick",
|
|
72
|
+
description: "Run a quick vulnerability scan (5-minute assessment, secrets + criticals) — deterministic scanner included",
|
|
73
|
+
inputSchema: {
|
|
74
|
+
type: "object",
|
|
75
|
+
properties: {
|
|
76
|
+
target: { type: "string", description: "URL, domain, or project path" },
|
|
64
77
|
},
|
|
78
|
+
required: ["target"],
|
|
65
79
|
},
|
|
66
|
-
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: "cyberaudit-list",
|
|
83
|
+
description: "List all available audit types and check installation",
|
|
84
|
+
inputSchema: { type: "object", properties: {} },
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
export const capabilities = {
|
|
88
|
+
tools: MCP_TOOLS,
|
|
67
89
|
};
|
|
68
90
|
function write(id, result) {
|
|
69
91
|
process.stdout.write(JSON.stringify({ jsonrpc: "2.0", id, ...result }) + "\n");
|
|
70
92
|
}
|
|
71
93
|
function handleToolCall(id, name, args) {
|
|
72
94
|
const auditType = name.replace("cyberaudit-", "");
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
{
|
|
76
|
-
|
|
77
|
-
|
|
95
|
+
if (name === "cyberaudit-list") {
|
|
96
|
+
write(id, {
|
|
97
|
+
result: {
|
|
98
|
+
content: [
|
|
99
|
+
{
|
|
100
|
+
type: "text",
|
|
101
|
+
text: `═══ CyberAudit ${VERSION} — Available Audits ═══
|
|
78
102
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
103
|
+
• cyberaudit-web: OWASP Top 10 web app audit
|
|
104
|
+
• cyberaudit-mobile: OWASP MASVS mobile audit
|
|
105
|
+
• cyberaudit-api: OWASP API Top 10 audit
|
|
106
|
+
• cyberaudit-cloud: Cloud config audit (S3, IAM, SG, storage)
|
|
107
|
+
• cyberaudit-quick: Quick 5-minute scan (secrets + criticals) — DETERMINISTIC SCANNER
|
|
108
|
+
• cyberaudit-full: Full stack (web + api + cloud) via /audit
|
|
82
109
|
|
|
110
|
+
Skill location: ${SKILL_DIR}
|
|
111
|
+
Docs: https://github.com/ArisRoman/cyberaudit-skill
|
|
112
|
+
Scanner: deterministic secrets detection 15 patterns`,
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (name === "cyberaudit-quick" && args.target) {
|
|
120
|
+
try {
|
|
121
|
+
const targetPath = resolve(args.target);
|
|
122
|
+
if (existsSync(targetPath)) {
|
|
123
|
+
const stat = statSync(targetPath);
|
|
124
|
+
if (stat.isDirectory() || stat.isFile()) {
|
|
125
|
+
const secretFindings = scanSecrets(targetPath);
|
|
126
|
+
const webFindings = scanWeb(targetPath);
|
|
127
|
+
const secretReport = formatFindingsText(secretFindings, args.target);
|
|
128
|
+
const webReport = formatWebFindingsText(webFindings, args.target);
|
|
129
|
+
write(id, {
|
|
130
|
+
result: {
|
|
131
|
+
content: [
|
|
132
|
+
{
|
|
133
|
+
type: "text",
|
|
134
|
+
text: `▶ CyberAudit ${VERSION}: QUICK deterministic scan completed\n\n${secretReport}\n${webReport}\n---\nTotal: ${secretFindings.length + webFindings.length} findings (secrets:${secretFindings.length} web:${webFindings.length})\nFor full context-aware audit, load skill and run:\n/${name} "${args.target}"\n\nSkill location: ${SKILL_DIR}\nChecklist: ${SKILL_DIR}/cloud/CLOUD-CHECKLIST.md\nCLI: npx cyberaudit-skill scan "${args.target}" --json`,
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
console.error(`[CyberAudit] Quick scan failed for ${args.target}: ${e.message}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
write(id, {
|
|
148
|
+
result: {
|
|
149
|
+
content: [
|
|
150
|
+
{
|
|
151
|
+
type: "text",
|
|
152
|
+
text: `▶ CyberAudit ${VERSION}: ${auditType.toUpperCase()} audit requested
|
|
153
|
+
|
|
154
|
+
Target: ${args.target || "not provided"}
|
|
155
|
+
${args.depth ? `Depth: ${args.depth}\n` : ""}${args.platform ? `Platform: ${args.platform}\n` : ""}
|
|
83
156
|
To execute the full audit, load the CyberAudit Skill and run:
|
|
84
157
|
|
|
85
|
-
/${name} "${args.target}"
|
|
158
|
+
/${name} "${args.target || "."}"
|
|
86
159
|
|
|
87
160
|
The skill will guide you through all checks, scoring, and report generation.
|
|
88
161
|
|
|
89
|
-
Skill location: ${SKILL_DIR}
|
|
90
|
-
|
|
91
|
-
|
|
162
|
+
Skill location: ${SKILL_DIR}
|
|
163
|
+
Cloud checklist: ${SKILL_DIR}/cloud/CLOUD-CHECKLIST.md
|
|
164
|
+
Secrets scanner: npx cyberaudit-skill scan "${args.target || "."}"`,
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
},
|
|
92
168
|
});
|
|
93
169
|
}
|
|
94
|
-
|
|
95
|
-
rl
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
170
|
+
export function startMcpServer() {
|
|
171
|
+
const rl = createInterface({ input: process.stdin });
|
|
172
|
+
rl.on("line", (line) => {
|
|
173
|
+
try {
|
|
174
|
+
const trimmed = line.trim();
|
|
175
|
+
if (!trimmed)
|
|
176
|
+
return;
|
|
177
|
+
const msg = JSON.parse(trimmed);
|
|
178
|
+
const id = msg.id;
|
|
179
|
+
switch (msg.method) {
|
|
180
|
+
case "initialize":
|
|
181
|
+
write(id, {
|
|
182
|
+
result: {
|
|
183
|
+
protocolVersion: "2024-11-05",
|
|
184
|
+
capabilities,
|
|
185
|
+
serverInfo: { name: "cyberaudit-skill", version: VERSION },
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
break;
|
|
189
|
+
case "tools/list":
|
|
190
|
+
write(id, {
|
|
191
|
+
result: capabilities,
|
|
192
|
+
});
|
|
193
|
+
break;
|
|
194
|
+
case "tools/call":
|
|
195
|
+
handleToolCall(id, msg.params?.name, msg.params?.arguments || {});
|
|
196
|
+
break;
|
|
197
|
+
case "notifications/initialized":
|
|
198
|
+
break;
|
|
199
|
+
default:
|
|
200
|
+
if (id !== undefined) {
|
|
201
|
+
write(id, { error: { code: -32601, message: `Method not found: ${msg.method}` } });
|
|
202
|
+
}
|
|
203
|
+
}
|
|
118
204
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
process.on("
|
|
125
|
-
|
|
126
|
-
|
|
205
|
+
catch {
|
|
206
|
+
// ignore malformed
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
process.on("SIGINT", () => process.exit(0));
|
|
210
|
+
process.on("SIGTERM", () => process.exit(0));
|
|
211
|
+
console.error(`[CyberAudit] MCP server ready v${VERSION} | Skill: ${SKILL_DIR}`);
|
|
212
|
+
}
|
|
213
|
+
if (import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("mcp-server.js") || process.argv[1]?.endsWith("mcp-server.ts")) {
|
|
214
|
+
startMcpServer();
|
|
215
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
function runMcp(inputLines) {
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
const proc = spawn('node', [join(process.cwd(), 'dist', 'mcp-server.js')], {
|
|
7
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
8
|
+
});
|
|
9
|
+
let stdout = '';
|
|
10
|
+
let stderr = '';
|
|
11
|
+
proc.stdout.on('data', (d) => (stdout += d.toString()));
|
|
12
|
+
proc.stderr.on('data', (d) => (stderr += d.toString()));
|
|
13
|
+
proc.on('error', reject);
|
|
14
|
+
// Write lines
|
|
15
|
+
for (const line of inputLines) {
|
|
16
|
+
proc.stdin.write(line + '\n');
|
|
17
|
+
}
|
|
18
|
+
setTimeout(() => {
|
|
19
|
+
proc.kill();
|
|
20
|
+
resolve({ stdout, stderr });
|
|
21
|
+
}, 800);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
describe('MCP Server', () => {
|
|
25
|
+
it('should respond to initialize', async () => {
|
|
26
|
+
const { stdout, stderr } = await runMcp([
|
|
27
|
+
JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'initialize', params: {} }),
|
|
28
|
+
]);
|
|
29
|
+
expect(stdout).toContain('protocolVersion');
|
|
30
|
+
expect(stdout).toContain('cyberaudit-skill');
|
|
31
|
+
expect(stderr).toContain('MCP server ready');
|
|
32
|
+
const lines = stdout.trim().split('\n').filter(Boolean);
|
|
33
|
+
const first = JSON.parse(lines[0]);
|
|
34
|
+
expect(first.result.serverInfo.version).toMatch(/\d+\.\d+\.\d+/);
|
|
35
|
+
// Should read version from package.json (3.1.5)
|
|
36
|
+
expect(first.result.serverInfo.version).toBe('3.1.5');
|
|
37
|
+
});
|
|
38
|
+
it('should list 6 tools including cloud', async () => {
|
|
39
|
+
const { stdout } = await runMcp([
|
|
40
|
+
JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'initialize', params: {} }),
|
|
41
|
+
JSON.stringify({ jsonrpc: '2.0', id: 2, method: 'tools/list', params: {} }),
|
|
42
|
+
]);
|
|
43
|
+
const lines = stdout.trim().split('\n').filter(Boolean).map(l => JSON.parse(l));
|
|
44
|
+
const listResp = lines.find(r => r.id === 2);
|
|
45
|
+
expect(listResp).toBeDefined();
|
|
46
|
+
const toolNames = listResp.result.tools.map((t) => t.name);
|
|
47
|
+
expect(toolNames).toContain('cyberaudit-web');
|
|
48
|
+
expect(toolNames).toContain('cyberaudit-cloud');
|
|
49
|
+
expect(toolNames).toContain('cyberaudit-quick');
|
|
50
|
+
expect(toolNames.length).toBeGreaterThanOrEqual(6);
|
|
51
|
+
});
|
|
52
|
+
it('should handle cloud tool call', async () => {
|
|
53
|
+
const { stdout } = await runMcp([
|
|
54
|
+
JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'initialize', params: {} }),
|
|
55
|
+
JSON.stringify({
|
|
56
|
+
jsonrpc: '2.0',
|
|
57
|
+
id: 2,
|
|
58
|
+
method: 'tools/call',
|
|
59
|
+
params: { name: 'cyberaudit-cloud', arguments: { target: 'terraform/' } },
|
|
60
|
+
}),
|
|
61
|
+
]);
|
|
62
|
+
const lines = stdout.trim().split('\n').filter(Boolean).map(l => JSON.parse(l));
|
|
63
|
+
const callResp = lines.find(r => r.id === 2);
|
|
64
|
+
expect(callResp).toBeDefined();
|
|
65
|
+
const text = callResp.result.content[0].text;
|
|
66
|
+
expect(text).toContain('CLOUD');
|
|
67
|
+
expect(text).toContain('terraform/');
|
|
68
|
+
expect(text).toContain('CLOUD-CHECKLIST.md');
|
|
69
|
+
});
|
|
70
|
+
it('should use single source of truth (no duplicate implementation in cli)', async () => {
|
|
71
|
+
// cli.ts should import from mcp-server.js
|
|
72
|
+
const fs = await import('fs');
|
|
73
|
+
const cliContent = fs.readFileSync(join(process.cwd(), 'src', 'cli.ts'), 'utf-8');
|
|
74
|
+
expect(cliContent).toContain('from "./mcp-server.js"');
|
|
75
|
+
expect(cliContent).not.toContain('msg.para'); // old buggy truncation
|
|
76
|
+
});
|
|
77
|
+
});
|